aboutsummaryrefslogtreecommitdiffstats
path: root/tools/hv/hv_kvp_daemon.c
diff options
context:
space:
mode:
authorK. Y. Srinivasan <kys@microsoft.com>2012-03-16 11:02:26 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-16 16:36:04 -0400
commitdb425334e5bb7fa65bbbd7bea9d79842f65bcf45 (patch)
tree0212936fd1e93ae8ad009cded3b783b0f7b0711e /tools/hv/hv_kvp_daemon.c
parentfa3d5b85c681518b6e4ec515814dcb2d5b702b89 (diff)
Tools: hv: Fully support the new KVP verbs in the user level daemon
Now fully support the new KVP messages in the user level daemon. Hyper-V defines multiple persistent pools to which the host can write/read/modify KVP tuples. In this patch we implement a file for each specified pool, where the KVP tuples will be stored in the guest. Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'tools/hv/hv_kvp_daemon.c')
-rw-r--r--tools/hv/hv_kvp_daemon.c281
1 files changed, 280 insertions, 1 deletions
diff --git a/tools/hv/hv_kvp_daemon.c b/tools/hv/hv_kvp_daemon.c
index a98878c874b..2fb9c3d09d7 100644
--- a/tools/hv/hv_kvp_daemon.c
+++ b/tools/hv/hv_kvp_daemon.c
@@ -39,7 +39,8 @@
39#include <ifaddrs.h> 39#include <ifaddrs.h>
40#include <netdb.h> 40#include <netdb.h>
41#include <syslog.h> 41#include <syslog.h>
42 42#include <sys/stat.h>
43#include <fcntl.h>
43 44
44/* 45/*
45 * KVP protocol: The user mode component first registers with the 46 * KVP protocol: The user mode component first registers with the
@@ -79,6 +80,250 @@ static char *os_build;
79static char *lic_version; 80static char *lic_version;
80static struct utsname uts_buf; 81static struct utsname uts_buf;
81 82
83
84#define MAX_FILE_NAME 100
85#define ENTRIES_PER_BLOCK 50
86
87struct kvp_record {
88 __u8 key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
89 __u8 value[HV_KVP_EXCHANGE_MAX_VALUE_SIZE];
90};
91
92struct kvp_file_state {
93 int fd;
94 int num_blocks;
95 struct kvp_record *records;
96 int num_records;
97 __u8 fname[MAX_FILE_NAME];
98};
99
100static struct kvp_file_state kvp_file_info[KVP_POOL_COUNT];
101
102static void kvp_acquire_lock(int pool)
103{
104 struct flock fl = {F_WRLCK, SEEK_SET, 0, 0, 0};
105 fl.l_pid = getpid();
106
107 if (fcntl(kvp_file_info[pool].fd, F_SETLKW, &fl) == -1) {
108 syslog(LOG_ERR, "Failed to acquire the lock pool: %d", pool);
109 exit(-1);
110 }
111}
112
113static void kvp_release_lock(int pool)
114{
115 struct flock fl = {F_UNLCK, SEEK_SET, 0, 0, 0};
116 fl.l_pid = getpid();
117
118 if (fcntl(kvp_file_info[pool].fd, F_SETLK, &fl) == -1) {
119 perror("fcntl");
120 syslog(LOG_ERR, "Failed to release the lock pool: %d", pool);
121 exit(-1);
122 }
123}
124
125static void kvp_update_file(int pool)
126{
127 FILE *filep;
128 size_t bytes_written;
129
130 /*
131 * We are going to write our in-memory registry out to
132 * disk; acquire the lock first.
133 */
134 kvp_acquire_lock(pool);
135
136 filep = fopen(kvp_file_info[pool].fname, "w");
137 if (!filep) {
138 kvp_release_lock(pool);
139 syslog(LOG_ERR, "Failed to open file, pool: %d", pool);
140 exit(-1);
141 }
142
143 bytes_written = fwrite(kvp_file_info[pool].records,
144 sizeof(struct kvp_record),
145 kvp_file_info[pool].num_records, filep);
146
147 fflush(filep);
148 kvp_release_lock(pool);
149}
150
151static int kvp_file_init(void)
152{
153 int ret, fd;
154 FILE *filep;
155 size_t records_read;
156 __u8 *fname;
157 struct kvp_record *record;
158 struct kvp_record *readp;
159 int num_blocks;
160 int i;
161 int alloc_unit = sizeof(struct kvp_record) * ENTRIES_PER_BLOCK;
162
163 if (access("/var/opt/hyperv", F_OK)) {
164 if (mkdir("/var/opt/hyperv", S_IRUSR | S_IWUSR | S_IROTH)) {
165 syslog(LOG_ERR, " Failed to create /var/opt/hyperv");
166 exit(-1);
167 }
168 }
169
170 for (i = 0; i < KVP_POOL_COUNT; i++) {
171 fname = kvp_file_info[i].fname;
172 records_read = 0;
173 num_blocks = 1;
174 sprintf(fname, "/var/opt/hyperv/.kvp_pool_%d", i);
175 fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IROTH);
176
177 if (fd == -1)
178 return 1;
179
180
181 filep = fopen(fname, "r");
182 if (!filep)
183 return 1;
184
185 record = malloc(alloc_unit * num_blocks);
186 if (record == NULL) {
187 fclose(filep);
188 return 1;
189 }
190 while (!feof(filep)) {
191 readp = &record[records_read];
192 records_read += fread(readp, sizeof(struct kvp_record),
193 ENTRIES_PER_BLOCK,
194 filep);
195
196 if (!feof(filep)) {
197 /*
198 * We have more data to read.
199 */
200 num_blocks++;
201 record = realloc(record, alloc_unit *
202 num_blocks);
203 if (record == NULL) {
204 fclose(filep);
205 return 1;
206 }
207 continue;
208 }
209 break;
210 }
211 kvp_file_info[i].fd = fd;
212 kvp_file_info[i].num_blocks = num_blocks;
213 kvp_file_info[i].records = record;
214 kvp_file_info[i].num_records = records_read;
215 fclose(filep);
216
217 }
218
219 return 0;
220}
221
222static int kvp_key_delete(int pool, __u8 *key, int key_size)
223{
224 int i;
225 int j, k;
226 int num_records = kvp_file_info[pool].num_records;
227 struct kvp_record *record = kvp_file_info[pool].records;
228
229 for (i = 0; i < num_records; i++) {
230 if (memcmp(key, record[i].key, key_size))
231 continue;
232 /*
233 * Found a match; just move the remaining
234 * entries up.
235 */
236 if (i == num_records) {
237 kvp_file_info[pool].num_records--;
238 kvp_update_file(pool);
239 return 0;
240 }
241
242 j = i;
243 k = j + 1;
244 for (; k < num_records; k++) {
245 strcpy(record[j].key, record[k].key);
246 strcpy(record[j].value, record[k].value);
247 j++;
248 }
249
250 kvp_file_info[pool].num_records--;
251 kvp_update_file(pool);
252 return 0;
253 }
254 return 1;
255}
256
257static int kvp_key_add_or_modify(int pool, __u8 *key, int key_size, __u8 *value,
258 int value_size)
259{
260 int i;
261 int j, k;
262 int num_records = kvp_file_info[pool].num_records;
263 struct kvp_record *record = kvp_file_info[pool].records;
264 int num_blocks = kvp_file_info[pool].num_blocks;
265
266 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
267 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
268 return 1;
269
270 for (i = 0; i < num_records; i++) {
271 if (memcmp(key, record[i].key, key_size))
272 continue;
273 /*
274 * Found a match; just update the value -
275 * this is the modify case.
276 */
277 memcpy(record[i].value, value, value_size);
278 kvp_update_file(pool);
279 return 0;
280 }
281
282 /*
283 * Need to add a new entry;
284 */
285 if (num_records == (ENTRIES_PER_BLOCK * num_blocks)) {
286 /* Need to allocate a larger array for reg entries. */
287 record = realloc(record, sizeof(struct kvp_record) *
288 ENTRIES_PER_BLOCK * (num_blocks + 1));
289
290 if (record == NULL)
291 return 1;
292 kvp_file_info[pool].num_blocks++;
293
294 }
295 memcpy(record[i].value, value, value_size);
296 memcpy(record[i].key, key, key_size);
297 kvp_file_info[pool].records = record;
298 kvp_file_info[pool].num_records++;
299 kvp_update_file(pool);
300 return 0;
301}
302
303static int kvp_get_value(int pool, __u8 *key, int key_size, __u8 *value,
304 int value_size)
305{
306 int i;
307 int num_records = kvp_file_info[pool].num_records;
308 struct kvp_record *record = kvp_file_info[pool].records;
309
310 if ((key_size > HV_KVP_EXCHANGE_MAX_KEY_SIZE) ||
311 (value_size > HV_KVP_EXCHANGE_MAX_VALUE_SIZE))
312 return 1;
313
314 for (i = 0; i < num_records; i++) {
315 if (memcmp(key, record[i].key, key_size))
316 continue;
317 /*
318 * Found a match; just copy the value out.
319 */
320 memcpy(value, record[i].value, value_size);
321 return 0;
322 }
323
324 return 1;
325}
326
82void kvp_get_os_info(void) 327void kvp_get_os_info(void)
83{ 328{
84 FILE *file; 329 FILE *file;
@@ -315,6 +560,11 @@ int main(void)
315 */ 560 */
316 kvp_get_os_info(); 561 kvp_get_os_info();
317 562
563 if (kvp_file_init()) {
564 syslog(LOG_ERR, "Failed to initialize the pools");
565 exit(-1);
566 }
567
318 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); 568 fd = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
319 if (fd < 0) { 569 if (fd < 0) {
320 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd); 570 syslog(LOG_ERR, "netlink socket creation failed; error:%d", fd);
@@ -389,9 +639,38 @@ int main(void)
389 } 639 }
390 continue; 640 continue;
391 641
642 /*
643 * The current protocol with the kernel component uses a
644 * NULL key name to pass an error condition.
645 * For the SET, GET and DELETE operations,
646 * use the existing protocol to pass back error.
647 */
648
392 case KVP_OP_SET: 649 case KVP_OP_SET:
650 if (kvp_key_add_or_modify(hv_msg->kvp_hdr.pool,
651 hv_msg->body.kvp_set.data.key,
652 hv_msg->body.kvp_set.data.key_size,
653 hv_msg->body.kvp_set.data.value,
654 hv_msg->body.kvp_set.data.value_size))
655 strcpy(hv_msg->body.kvp_set.data.key, "");
656 break;
657
393 case KVP_OP_GET: 658 case KVP_OP_GET:
659 if (kvp_get_value(hv_msg->kvp_hdr.pool,
660 hv_msg->body.kvp_set.data.key,
661 hv_msg->body.kvp_set.data.key_size,
662 hv_msg->body.kvp_set.data.value,
663 hv_msg->body.kvp_set.data.value_size))
664 strcpy(hv_msg->body.kvp_set.data.key, "");
665 break;
666
394 case KVP_OP_DELETE: 667 case KVP_OP_DELETE:
668 if (kvp_key_delete(hv_msg->kvp_hdr.pool,
669 hv_msg->body.kvp_delete.key,
670 hv_msg->body.kvp_delete.key_size))
671 strcpy(hv_msg->body.kvp_delete.key, "");
672 break;
673
395 default: 674 default:
396 break; 675 break;
397 } 676 }