win-pvdrivers

view xenpci/xenbus.c @ 1106:2d392ecdd366

Fix race is xenvbd causing 30 second freeze under high load
author James Harper <james.harper@bendigoit.com.au>
date Tue Nov 11 23:08:11 2014 +1100 (2014-11-11)
parents 27bd2a5a4704
children
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
4 Copyright (c) 2014, James Harper
5 All rights reserved.
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of James Harper nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL JAMES HARPER BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
30 #include "xenpci.h"
31 #include <stdlib.h>
33 #pragma warning( disable : 4204 )
34 #pragma warning( disable : 4221 )
36 /* Not really necessary but keeps PREfast happy */
37 static EVT_WDF_WORKITEM XenBus_WatchWorkItemProc;
39 WDF_DECLARE_CONTEXT_TYPE(xsd_sockmsg_t)
41 struct write_req {
42 void *data;
43 unsigned len;
44 };
46 // This routine free's the rep structure if there was an error!!!
47 static char *errmsg(struct xsd_sockmsg *rep)
48 {
49 char *res;
51 if (!rep) {
52 char msg[] = "No reply";
53 size_t len = strlen(msg) + 1;
54 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
55 }
56 if (rep->type != XS_ERROR)
57 return NULL;
58 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
59 memcpy(res, rep + 1, rep->len);
60 res[rep->len] = 0;
61 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
62 return res;
63 }
65 static void memcpy_from_ring(void *Ring,
66 void *Dest,
67 int off,
68 int len)
69 {
70 int c1, c2;
71 char *ring = Ring;
72 char *dest = Dest;
73 c1 = min(len, XENSTORE_RING_SIZE - off);
74 c2 = len - c1;
75 memcpy(dest, ring + off, c1);
76 memcpy(dest + c1, ring, c2);
77 }
79 /* called with xenbus_mutex held */
80 static void xb_write(
81 PXENPCI_DEVICE_DATA xpdd,
82 PVOID data,
83 ULONG len
84 )
85 {
86 XENSTORE_RING_IDX prod;
87 ULONG copy_len;
88 PUCHAR ptr;
89 ULONG remaining;
91 //FUNCTION_ENTER();
93 XN_ASSERT(len <= XENSTORE_RING_SIZE);
94 prod = xpdd->xen_store_interface->req_prod;
95 ptr = data;
96 remaining = len;
97 while (remaining)
98 {
99 copy_len = min(remaining, XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
100 memcpy((PUCHAR)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), ptr, copy_len);
101 prod += (XENSTORE_RING_IDX)copy_len;
102 ptr += copy_len;
103 remaining -= copy_len;
104 }
105 /* Remote must see entire message before updating indexes */
106 KeMemoryBarrier();
107 xpdd->xen_store_interface->req_prod = prod;
108 EvtChn_Notify(xpdd, xpdd->xenbus_event);
110 //FUNCTION_EXIT();
111 }
113 /* takes and releases xb_request_mutex */
114 static struct xsd_sockmsg *
115 xenbus_format_msg_reply(
116 PXENPCI_DEVICE_DATA xpdd,
117 int type,
118 xenbus_transaction_t trans_id,
119 struct write_req *req,
120 int nr_reqs)
121 {
122 struct xsd_sockmsg msg;
123 struct xsd_sockmsg *reply;
124 int i;
126 //FUNCTION_ENTER();
128 msg.type = type;
129 msg.req_id = 0;
130 msg.tx_id = trans_id;
131 msg.len = 0;
132 for (i = 0; i < nr_reqs; i++)
133 msg.len += req[i].len;
135 ExAcquireFastMutex(&xpdd->xb_request_mutex);
136 xb_write(xpdd, &msg, sizeof(msg));
137 for (i = 0; i < nr_reqs; i++)
138 xb_write(xpdd, req[i].data, req[i].len);
140 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
141 reply = xpdd->xb_reply;
142 xpdd->xb_reply = NULL;
143 ExReleaseFastMutex(&xpdd->xb_request_mutex);
145 //FUNCTION_EXIT();
147 return reply;
148 }
150 /* takes and releases xb_request_mutex */
151 struct xsd_sockmsg *
152 XenBus_Raw(
153 PXENPCI_DEVICE_DATA xpdd,
154 struct xsd_sockmsg *msg)
155 {
156 struct xsd_sockmsg *reply;
158 //FUNCTION_ENTER();
160 ExAcquireFastMutex(&xpdd->xb_request_mutex);
161 xb_write(xpdd, msg, sizeof(struct xsd_sockmsg) + msg->len);
162 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
163 reply = xpdd->xb_reply;
164 xpdd->xb_reply = NULL;
165 ExReleaseFastMutex(&xpdd->xb_request_mutex);
167 //FUNCTION_EXIT();
169 return reply;
170 }
172 /* Called at PASSIVE_LEVEL */
173 char *
174 XenBus_Read(
175 PVOID Context,
176 xenbus_transaction_t xbt,
177 char *path,
178 char **value)
179 {
180 PXENPCI_DEVICE_DATA xpdd = Context;
181 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
182 struct xsd_sockmsg *rep;
183 char *res;
184 char *msg;
186 //FUNCTION_ENTER();
188 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
190 rep = xenbus_format_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
191 msg = errmsg(rep);
192 if (msg) {
193 *value = NULL;
194 return msg;
195 }
196 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
197 memcpy(res, rep + 1, rep->len);
198 res[rep->len] = 0;
199 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
200 *value = res;
202 FUNCTION_EXIT();
204 return NULL;
205 }
207 /* Called at PASSIVE_LEVEL */
208 char *
209 XenBus_Write(
210 PVOID Context,
211 xenbus_transaction_t xbt,
212 char *path,
213 char *value)
214 {
215 PXENPCI_DEVICE_DATA xpdd = Context;
216 struct write_req req[] = {
217 {path, (ULONG)strlen(path) + 1},
218 {value, (ULONG)strlen(value)},
219 };
220 struct xsd_sockmsg *rep;
221 char *msg;
223 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
225 rep = xenbus_format_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
226 msg = errmsg(rep);
227 if (msg)
228 return msg;
229 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
231 return NULL;
232 }
234 /* Called at PASSIVE_LEVEL */
235 static VOID
236 XenBus_WatchWorkItemProc(WDFWORKITEM workitem)
237 {
238 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
239 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
240 xsd_sockmsg_t *msg;
241 PCHAR path;
242 int index;
243 PXENBUS_WATCH_ENTRY entry;
244 PXN_WATCH_CALLBACK service_routine;
245 PVOID service_context;
247 //FUNCTION_ENTER();
248 msg = WdfObjectGetTypedContext(workitem, xsd_sockmsg_t);
249 path = (PCHAR)msg + sizeof(xsd_sockmsg_t);
250 index = atoi(path + strlen(path) + 1);
251 if (index < 0 || index >= MAX_WATCH_ENTRIES)
252 {
253 FUNCTION_MSG("Watch index %d out of range\n", index);
254 WdfObjectDelete(workitem);
255 //FUNCTION_ENTER();
256 return;
257 }
258 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
259 entry = &xpdd->XenBus_WatchEntries[index];
260 if (!entry->Active || !entry->ServiceRoutine)
261 {
262 FUNCTION_MSG("No watch for index %d\n", index);
263 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
264 WdfObjectDelete(workitem);
265 //FUNCTION_ENTER();
266 return;
267 }
268 entry->Count++;
269 service_routine = entry->ServiceRoutine;
270 service_context = entry->ServiceContext;
271 service_routine(path, service_context);
272 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
273 WdfObjectDelete(workitem);
274 //FUNCTION_EXIT();
275 }
277 /* Called at DISPATCH_LEVEL */
278 static VOID
279 XenBus_Dpc(PVOID ServiceContext)
280 {
281 NTSTATUS status;
282 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
283 xsd_sockmsg_t msg;
284 ULONG msg_len;
285 WDF_WORKITEM_CONFIG workitem_config;
286 WDF_OBJECT_ATTRIBUTES workitem_attributes;
287 WDFWORKITEM workitem;
288 ULONG rsp_prod;
290 //FUNCTION_ENTER();
292 KeAcquireSpinLockAtDpcLevel(&xpdd->xb_ring_spinlock);
294 /* snapshot rsp_prod so it doesn't change while we are looking at it */
295 while ((rsp_prod = xpdd->xen_store_interface->rsp_prod) != xpdd->xen_store_interface->rsp_cons)
296 {
297 KeMemoryBarrier(); /* make sure the data in the ring is valid */
298 if (!xpdd->xb_msg)
299 {
300 if (rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(xsd_sockmsg_t))
301 {
302 //FUNCTION_MSG("Message incomplete (not even a full header)\n");
303 break;
304 }
305 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
306 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(xsd_sockmsg_t));
307 xpdd->xb_msg = ExAllocatePoolWithTag(NonPagedPool, sizeof(xsd_sockmsg_t) + msg.len, XENPCI_POOL_TAG);
308 memcpy(xpdd->xb_msg, &msg, sizeof(xsd_sockmsg_t));
309 xpdd->xb_msg_offset = sizeof(xsd_sockmsg_t);
310 xpdd->xen_store_interface->rsp_cons += sizeof(xsd_sockmsg_t);
311 }
313 msg_len = min(rsp_prod - xpdd->xen_store_interface->rsp_cons, sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len - xpdd->xb_msg_offset);
314 XN_ASSERT(xpdd->xb_msg_offset + msg_len <= sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len);
315 memcpy_from_ring(xpdd->xen_store_interface->rsp,
316 (PUCHAR)xpdd->xb_msg + xpdd->xb_msg_offset,
317 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
318 msg_len);
319 xpdd->xen_store_interface->rsp_cons += msg_len;
320 xpdd->xb_msg_offset += msg_len;
322 if (xpdd->xb_msg_offset < sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len)
323 {
324 //FUNCTION_MSG("Message incomplete (header but not full body)\n");
325 EvtChn_Notify(xpdd, xpdd->xenbus_event); /* there is room on the ring now */
326 break;
327 }
329 if (xpdd->xb_msg->type != XS_WATCH_EVENT)
330 {
331 /* process reply - only ever one outstanding */
332 XN_ASSERT(xpdd->xb_reply == NULL);
333 xpdd->xb_reply = xpdd->xb_msg;
334 xpdd->xb_msg = NULL;
335 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
336 }
337 else
338 {
339 /* process watch */
340 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenBus_WatchWorkItemProc);
341 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&workitem_attributes, xsd_sockmsg_t);
342 workitem_attributes.ParentObject = xpdd->wdf_device;
343 workitem_attributes.ContextSizeOverride = xpdd->xb_msg_offset;
344 status = WdfWorkItemCreate(&workitem_config, &workitem_attributes, &workitem);
345 if (!NT_SUCCESS(status))
346 {
347 FUNCTION_MSG("Failed to create work item for watch\n");
348 continue;
349 }
350 memcpy(WdfObjectGetTypedContext(workitem, xsd_sockmsg_t), xpdd->xb_msg, xpdd->xb_msg_offset);
351 xpdd->xb_msg = NULL;
352 WdfWorkItemEnqueue(workitem);
353 }
354 EvtChn_Notify(xpdd, xpdd->xenbus_event); /* there is room on the ring now */
355 }
356 KeReleaseSpinLockFromDpcLevel(&xpdd->xb_ring_spinlock);
358 //FUNCTION_EXIT();
359 }
361 static NTSTATUS
362 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
363 {
364 PHYSICAL_ADDRESS pa_xen_store_interface;
365 xen_ulong_t xen_store_mfn;
367 xpdd->xenbus_event = (evtchn_port_t)hvm_get_parameter(HVM_PARAM_STORE_EVTCHN);
368 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(HVM_PARAM_STORE_PFN);
369 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
370 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
372 EvtChn_BindDpc(xpdd, xpdd->xenbus_event, XenBus_Dpc, xpdd, EVT_ACTION_FLAGS_NO_SUSPEND);
374 return STATUS_SUCCESS;
375 }
377 static NTSTATUS
378 XenBus_Disconnect(PXENPCI_DEVICE_DATA xpdd)
379 {
380 EvtChn_Unbind(xpdd, xpdd->xenbus_event);
382 MmUnmapIoSpace(xpdd->xen_store_interface, PAGE_SIZE);
384 return STATUS_SUCCESS;
385 }
387 NTSTATUS
388 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
389 {
390 NTSTATUS status;
391 int i;
393 FUNCTION_ENTER();
395 XN_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
397 KeInitializeSpinLock(&xpdd->xb_ring_spinlock);
398 ExInitializeFastMutex(&xpdd->xb_request_mutex);
399 ExInitializeFastMutex(&xpdd->xb_watch_mutex);
401 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
402 {
403 xpdd->XenBus_WatchEntries[i].Active = 0;
404 }
406 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE);
408 status = XenBus_Connect(xpdd);
409 if (!NT_SUCCESS(status))
410 {
411 FUNCTION_EXIT();
412 return status;
413 }
415 FUNCTION_EXIT();
417 return STATUS_SUCCESS;
418 }
420 char *
421 XenBus_SendRemWatch(
422 PVOID context,
423 xenbus_transaction_t xbt,
424 char *path,
425 int index)
426 {
427 struct xsd_sockmsg *rep;
428 char *msg;
429 char Token[20];
430 struct write_req req[2];
432 req[0].data = path;
433 req[0].len = (ULONG)strlen(path) + 1;
435 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
436 req[1].data = Token;
437 req[1].len = (ULONG)strlen(Token) + 1;
439 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
441 msg = errmsg(rep);
442 if (msg)
443 return msg;
445 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
447 return NULL;
448 }
450 NTSTATUS
451 XenBus_Halt(PXENPCI_DEVICE_DATA xpdd)
452 {
453 int i;
455 FUNCTION_ENTER();
457 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
459 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
460 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
461 {
462 if (xpdd->XenBus_WatchEntries[i].Active)
463 {
464 xpdd->XenBus_WatchEntries[i].Active = 0;
465 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
466 }
467 }
469 XenBus_Disconnect(xpdd);
471 FUNCTION_EXIT();
473 return STATUS_SUCCESS;
474 }
476 char *
477 XenBus_List(
478 PVOID Context,
479 xenbus_transaction_t xbt,
480 char *pre,
481 char ***contents)
482 {
483 PXENPCI_DEVICE_DATA xpdd = Context;
484 struct xsd_sockmsg *reply, *repmsg;
485 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
486 ULONG nr_elems, x, i;
487 char **res;
488 char *msg;
490 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
492 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
493 msg = errmsg(repmsg);
494 if (msg)
495 {
496 *contents = NULL;
497 return msg;
498 }
499 reply = repmsg + 1;
500 for (x = nr_elems = 0; x < repmsg->len; x++)
501 {
502 nr_elems += (((char *)reply)[x] == 0);
503 }
504 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
505 XENPCI_POOL_TAG);
506 for (x = i = 0; i < nr_elems; i++)
507 {
508 int l = (int)strlen((char *)reply + x);
509 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
510 memcpy(res[i], (char *)reply + x, l + 1);
511 x += l + 1;
512 }
513 res[i] = NULL;
514 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
515 *contents = res;
517 return NULL;
518 }
520 /* Called at PASSIVE_LEVEL */
521 static char *
522 XenBus_SendAddWatch(
523 PVOID Context,
524 xenbus_transaction_t xbt,
525 char *Path,
526 int slot)
527 {
528 PXENPCI_DEVICE_DATA xpdd = Context;
529 struct xsd_sockmsg *rep;
530 char *msg;
531 char Token[20];
532 struct write_req req[2];
534 req[0].data = Path;
535 req[0].len = (ULONG)strlen(Path) + 1;
537 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
538 req[1].data = Token;
539 req[1].len = (ULONG)strlen(Token) + 1;
541 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
543 msg = errmsg(rep);
544 if (!msg)
545 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
547 return msg;
548 }
550 /* called at PASSIVE_LEVEL */
551 NTSTATUS
552 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
553 {
554 int i;
556 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
557 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
558 if (xpdd->XenBus_WatchEntries[i].Active)
559 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
560 }
561 XenBus_Disconnect(xpdd);
563 return STATUS_SUCCESS;
564 }
566 /* called at PASSIVE_LEVEL */
567 NTSTATUS
568 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
569 {
570 NTSTATUS status;
571 int i;
573 FUNCTION_ENTER();
575 status = XenBus_Connect(xpdd);
576 if (!NT_SUCCESS(status))
577 {
578 return status;
579 }
581 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
582 {
583 if (xpdd->XenBus_WatchEntries[i].Active)
584 {
585 FUNCTION_MSG("Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path);
586 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
587 }
588 }
590 FUNCTION_EXIT();
592 return STATUS_SUCCESS;
593 }
595 char *
596 XenBus_AddWatch(
597 PVOID Context,
598 xenbus_transaction_t xbt,
599 char *Path,
600 PXN_WATCH_CALLBACK ServiceRoutine,
601 PVOID ServiceContext)
602 {
603 PXENPCI_DEVICE_DATA xpdd = Context;
604 char *msg;
605 int i;
606 PXENBUS_WATCH_ENTRY w_entry;
608 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
610 XN_ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
612 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
614 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
615 if (xpdd->XenBus_WatchEntries[i].Active == 0)
616 break;
618 if (i == MAX_WATCH_ENTRIES)
619 {
620 FUNCTION_MSG("No more watch slots left\n");
621 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
622 return NULL;
623 }
625 /* must init watchentry before starting watch */
627 w_entry = &xpdd->XenBus_WatchEntries[i];
628 RtlStringCbCopyA(w_entry->Path, ARRAY_SIZE(w_entry->Path), Path);
629 w_entry->ServiceRoutine = ServiceRoutine;
630 w_entry->ServiceContext = ServiceContext;
631 w_entry->Count = 0;
632 w_entry->Active = 1;
634 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
636 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
638 if (msg)
639 {
640 xpdd->XenBus_WatchEntries[i].Active = 0;
641 return msg;
642 }
644 return NULL;
645 }
647 char *
648 XenBus_RemWatch(
649 PVOID Context,
650 xenbus_transaction_t xbt,
651 char *Path,
652 PXN_WATCH_CALLBACK ServiceRoutine,
653 PVOID ServiceContext) {
654 PXENPCI_DEVICE_DATA xpdd = Context;
655 char *msg;
656 int i;
658 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
660 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
662 // check that Path < 128 chars
664 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
665 if (xpdd->XenBus_WatchEntries[i].Active
666 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)
667 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
668 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext) {
669 FUNCTION_MSG("Match\n");
670 break;
671 }
672 }
674 if (i == MAX_WATCH_ENTRIES) {
675 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
676 FUNCTION_MSG("Watch not set for %s - can't remove\n", Path);
677 return NULL;
678 }
680 xpdd->XenBus_WatchEntries[i].Active = 0;
681 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
683 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
685 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
687 return msg;
688 }
690 char *
691 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
692 {
693 PXENPCI_DEVICE_DATA xpdd = Context;
694 /* xenstored becomes angry if you send a length 0 message, so just
695 shove a nul terminator on the end */
696 struct write_req req = { "", 1};
697 struct xsd_sockmsg *rep;
698 char *err;
700 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
702 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
703 err = errmsg(rep);
704 if (err)
705 return err;
706 *xbt = atoi((char *)(rep + 1));
707 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
709 return NULL;
710 }
712 char *
713 XenBus_EndTransaction(
714 PVOID Context,
715 xenbus_transaction_t t,
716 int abort,
717 int *retry)
718 {
719 PXENPCI_DEVICE_DATA xpdd = Context;
720 struct xsd_sockmsg *rep;
721 struct write_req req;
722 char *err;
724 *retry = 0;
726 req.data = abort ? "F" : "T";
727 req.len = 2;
728 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
729 err = errmsg(rep);
730 if (err) {
731 if (!strcmp(err, "EAGAIN")) {
732 *retry = 1;
733 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
734 return NULL;
735 } else {
736 return err;
737 }
738 }
739 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
741 return NULL;
742 }
744 char *
745 XenBus_Printf(
746 PVOID Context,
747 xenbus_transaction_t xbt,
748 char *path,
749 char *fmt,
750 ...)
751 {
752 PXENPCI_DEVICE_DATA xpdd = Context;
753 va_list ap;
754 char buf[512];
755 char *retval;
757 XN_ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
759 va_start(ap, fmt);
760 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
761 va_end(ap);
762 retval = XenBus_Write(xpdd, xbt, path, buf);
764 return retval;
765 }