win-pvdrivers

view xenpci/xenbus.c @ 683:4baaaaa23235

Fix a hang in xenbus when a flurry of activity fills the xenstore ring
author James Harper <james.harper@bendigoit.com.au>
date Sun Oct 11 00:21:41 2009 +1100 (2009-10-11)
parents e5522de3be37
children 5bdb7251370c
line source
1 /*
2 PV Drivers for Windows Xen HVM Domains
3 Copyright (C) 2007 James Harper
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
20 #include "xenpci.h"
21 #include <stdlib.h>
23 #pragma warning( disable : 4204 )
24 #pragma warning( disable : 4221 )
26 WDF_DECLARE_CONTEXT_TYPE(xsd_sockmsg_t)
28 struct write_req {
29 void *data;
30 unsigned len;
31 };
33 // This routine free's the rep structure if there was an error!!!
34 static char *errmsg(struct xsd_sockmsg *rep)
35 {
36 char *res;
38 if (!rep) {
39 char msg[] = "No reply";
40 size_t len = strlen(msg) + 1;
41 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
42 }
43 if (rep->type != XS_ERROR)
44 return NULL;
45 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
46 memcpy(res, rep + 1, rep->len);
47 res[rep->len] = 0;
48 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
49 return res;
50 }
52 static void memcpy_from_ring(void *Ring,
53 void *Dest,
54 int off,
55 int len)
56 {
57 int c1, c2;
58 char *ring = Ring;
59 char *dest = Dest;
60 c1 = min(len, XENSTORE_RING_SIZE - off);
61 c2 = len - c1;
62 memcpy(dest, ring + off, c1);
63 memcpy(dest + c1, ring, c2);
64 }
66 /* called with xenbus_mutex held */
67 static void xb_write(
68 PXENPCI_DEVICE_DATA xpdd,
69 PVOID data,
70 ULONG len
71 )
72 {
73 XENSTORE_RING_IDX prod;
74 ULONG copy_len;
75 PUCHAR ptr;
76 ULONG remaining;
78 //FUNCTION_ENTER();
80 ASSERT(len <= XENSTORE_RING_SIZE);
81 prod = xpdd->xen_store_interface->req_prod;
82 ptr = data;
83 remaining = len;
84 while (remaining)
85 {
86 copy_len = min(remaining, XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
87 memcpy((PUCHAR)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), ptr, copy_len);
88 prod += (XENSTORE_RING_IDX)copy_len;
89 ptr += copy_len;
90 remaining -= copy_len;
91 }
92 /* Remote must see entire message before updating indexes */
93 KeMemoryBarrier();
94 xpdd->xen_store_interface->req_prod = prod;
95 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn);
97 //FUNCTION_EXIT();
98 }
100 /* takes and releases xb_request_mutex */
101 static struct xsd_sockmsg *
102 xenbus_format_msg_reply(
103 PXENPCI_DEVICE_DATA xpdd,
104 int type,
105 xenbus_transaction_t trans_id,
106 struct write_req *req,
107 int nr_reqs)
108 {
109 struct xsd_sockmsg msg;
110 struct xsd_sockmsg *reply;
111 int i;
113 //FUNCTION_ENTER();
115 msg.type = type;
116 msg.req_id = 0;
117 msg.tx_id = trans_id;
118 msg.len = 0;
119 for (i = 0; i < nr_reqs; i++)
120 msg.len += req[i].len;
122 ExAcquireFastMutex(&xpdd->xb_request_mutex);
123 xb_write(xpdd, &msg, sizeof(msg));
124 for (i = 0; i < nr_reqs; i++)
125 xb_write(xpdd, req[i].data, req[i].len);
127 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
128 reply = xpdd->xb_reply;
129 xpdd->xb_reply = NULL;
130 ExReleaseFastMutex(&xpdd->xb_request_mutex);
132 //FUNCTION_EXIT();
134 return reply;
135 }
137 /* takes and releases xb_request_mutex */
138 struct xsd_sockmsg *
139 XenBus_Raw(
140 PXENPCI_DEVICE_DATA xpdd,
141 struct xsd_sockmsg *msg)
142 {
143 struct xsd_sockmsg *reply;
145 //FUNCTION_ENTER();
147 ExAcquireFastMutex(&xpdd->xb_request_mutex);
148 xb_write(xpdd, msg, sizeof(struct xsd_sockmsg) + msg->len);
149 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
150 reply = xpdd->xb_reply;
151 xpdd->xb_reply = NULL;
152 ExReleaseFastMutex(&xpdd->xb_request_mutex);
154 //FUNCTION_EXIT();
156 return reply;
157 }
159 /* Called at PASSIVE_LEVEL */
160 char *
161 XenBus_Read(
162 PVOID Context,
163 xenbus_transaction_t xbt,
164 char *path,
165 char **value)
166 {
167 PXENPCI_DEVICE_DATA xpdd = Context;
168 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
169 struct xsd_sockmsg *rep;
170 char *res;
171 char *msg;
173 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
175 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
177 rep = xenbus_format_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
178 msg = errmsg(rep);
179 if (msg) {
180 *value = NULL;
181 return msg;
182 }
183 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
184 memcpy(res, rep + 1, rep->len);
185 res[rep->len] = 0;
186 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
187 *value = res;
189 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
191 return NULL;
192 }
194 /* Called at PASSIVE_LEVEL */
195 char *
196 XenBus_Write(
197 PVOID Context,
198 xenbus_transaction_t xbt,
199 char *path,
200 char *value)
201 {
202 PXENPCI_DEVICE_DATA xpdd = Context;
203 struct write_req req[] = {
204 {path, (ULONG)strlen(path) + 1},
205 {value, (ULONG)strlen(value)},
206 };
207 struct xsd_sockmsg *rep;
208 char *msg;
210 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
212 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
214 rep = xenbus_format_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
215 msg = errmsg(rep);
216 if (msg)
217 return msg;
218 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
220 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
222 return NULL;
223 }
225 /* Called at PASSIVE_LEVEL */
226 static VOID
227 XenBus_WatchWorkItemProc(WDFWORKITEM workitem)
228 {
229 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
230 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
231 xsd_sockmsg_t *msg;
232 PCHAR path;
233 int index;
234 PXENBUS_WATCH_ENTRY entry;
236 //FUNCTION_ENTER();
237 msg = WdfObjectGetTypedContext(workitem, xsd_sockmsg_t);
238 path = (PCHAR)msg + sizeof(xsd_sockmsg_t);
239 index = atoi(path + strlen(path) + 1);
240 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
241 entry = &xpdd->XenBus_WatchEntries[index];
242 if (!entry->Active || !entry->ServiceRoutine)
243 {
244 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
245 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
246 WdfObjectDelete(workitem);
247 return;
248 }
249 entry->Count++;
250 entry->ServiceRoutine(path, entry->ServiceContext);
251 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
252 WdfObjectDelete(workitem);
253 //FUNCTION_ENTER();
254 }
256 /* Called at DISPATCH_LEVEL */
257 static VOID
258 XenBus_Dpc(PVOID ServiceContext)
259 {
260 NTSTATUS status;
261 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
262 xsd_sockmsg_t msg;
263 ULONG msg_len;
264 WDF_WORKITEM_CONFIG workitem_config;
265 WDF_OBJECT_ATTRIBUTES workitem_attributes;
266 WDFWORKITEM workitem;
268 //FUNCTION_ENTER();
270 KeAcquireSpinLockAtDpcLevel(&xpdd->xb_ring_spinlock);
272 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
273 {
274 if (!xpdd->xb_msg)
275 {
276 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(xsd_sockmsg_t))
277 {
278 KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
279 break;
280 }
281 KeMemoryBarrier();
282 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
283 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(xsd_sockmsg_t));
284 xpdd->xb_msg = ExAllocatePoolWithTag(NonPagedPool, sizeof(xsd_sockmsg_t) + msg.len, XENPCI_POOL_TAG);
285 memcpy(xpdd->xb_msg, &msg, sizeof(xsd_sockmsg_t));
286 xpdd->xb_msg_offset = sizeof(xsd_sockmsg_t);
287 xpdd->xen_store_interface->rsp_cons += sizeof(xsd_sockmsg_t);
288 }
290 msg_len = min(xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons, sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len - xpdd->xb_msg_offset);
291 KeMemoryBarrier(); /* make sure the data in the ring is valid */
292 ASSERT(xpdd->xb_msg_offset + msg_len <= sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len);
293 memcpy_from_ring(xpdd->xen_store_interface->rsp,
294 (PUCHAR)xpdd->xb_msg + xpdd->xb_msg_offset,
295 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
296 msg_len);
297 xpdd->xen_store_interface->rsp_cons += msg_len;
298 xpdd->xb_msg_offset += msg_len;
300 if (xpdd->xb_msg_offset < sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len)
301 {
302 KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
303 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn); /* there is room on the ring now */
304 break;
305 }
307 if (xpdd->xb_msg->type != XS_WATCH_EVENT)
308 {
309 /* process reply - only ever one outstanding */
310 ASSERT(xpdd->xb_reply == NULL);
311 xpdd->xb_reply = xpdd->xb_msg;
312 xpdd->xb_msg = NULL;
313 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
314 }
315 else
316 {
317 /* process watch */
318 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenBus_WatchWorkItemProc);
319 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&workitem_attributes, xsd_sockmsg_t);
320 workitem_attributes.ParentObject = xpdd->wdf_device;
321 workitem_attributes.ContextSizeOverride = xpdd->xb_msg_offset;
322 status = WdfWorkItemCreate(&workitem_config, &workitem_attributes, &workitem);
323 if (!NT_SUCCESS(status))
324 {
325 KdPrint((__DRIVER_NAME " Failed to create work item for watch\n"));
326 continue;
327 }
328 memcpy(WdfObjectGetTypedContext(workitem, xsd_sockmsg_t), xpdd->xb_msg, xpdd->xb_msg_offset);
329 xpdd->xb_msg = NULL;
330 WdfWorkItemEnqueue(workitem);
331 }
332 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn); /* there is room on the ring now */
333 }
334 KeReleaseSpinLockFromDpcLevel(&xpdd->xb_ring_spinlock);
336 //FUNCTION_EXIT();
337 }
339 static NTSTATUS
340 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
341 {
342 PHYSICAL_ADDRESS pa_xen_store_interface;
343 xen_ulong_t xen_store_mfn;
345 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
346 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
347 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
348 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
350 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
352 return STATUS_SUCCESS;
353 }
355 static NTSTATUS
356 XenBus_Disconnect(PXENPCI_DEVICE_DATA xpdd)
357 {
358 EvtChn_Unbind(xpdd, xpdd->xen_store_evtchn);
360 MmUnmapIoSpace(xpdd->xen_store_interface, PAGE_SIZE);
362 return STATUS_SUCCESS;
363 }
365 NTSTATUS
366 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
367 {
368 NTSTATUS status;
369 int i;
371 FUNCTION_ENTER();
373 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
375 KeInitializeSpinLock(&xpdd->xb_ring_spinlock);
376 ExInitializeFastMutex(&xpdd->xb_request_mutex);
377 ExInitializeFastMutex(&xpdd->xb_watch_mutex);
379 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
380 {
381 xpdd->XenBus_WatchEntries[i].Active = 0;
382 }
384 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE);
386 status = XenBus_Connect(xpdd);
387 if (!NT_SUCCESS(status))
388 {
389 FUNCTION_EXIT();
390 return status;
391 }
393 FUNCTION_EXIT();
395 return STATUS_SUCCESS;
396 }
398 char *
399 XenBus_SendRemWatch(
400 PVOID context,
401 xenbus_transaction_t xbt,
402 char *path,
403 int index)
404 {
405 struct xsd_sockmsg *rep;
406 char *msg;
407 char Token[20];
408 struct write_req req[2];
410 req[0].data = path;
411 req[0].len = (ULONG)strlen(path) + 1;
413 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
414 req[1].data = Token;
415 req[1].len = (ULONG)strlen(Token) + 1;
417 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
419 msg = errmsg(rep);
420 if (msg)
421 return msg;
423 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
425 return NULL;
426 }
428 NTSTATUS
429 XenBus_Halt(PXENPCI_DEVICE_DATA xpdd)
430 {
431 int i;
433 FUNCTION_ENTER();
435 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
437 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
438 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
439 {
440 if (xpdd->XenBus_WatchEntries[i].Active)
441 {
442 xpdd->XenBus_WatchEntries[i].Active = 0;
443 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
444 }
445 }
447 XenBus_Disconnect(xpdd);
449 FUNCTION_EXIT();
451 return STATUS_SUCCESS;
452 }
454 char *
455 XenBus_List(
456 PVOID Context,
457 xenbus_transaction_t xbt,
458 char *pre,
459 char ***contents)
460 {
461 PXENPCI_DEVICE_DATA xpdd = Context;
462 struct xsd_sockmsg *reply, *repmsg;
463 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
464 ULONG nr_elems, x, i;
465 char **res;
466 char *msg;
468 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
470 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
471 msg = errmsg(repmsg);
472 if (msg)
473 {
474 *contents = NULL;
475 return msg;
476 }
477 reply = repmsg + 1;
478 for (x = nr_elems = 0; x < repmsg->len; x++)
479 {
480 nr_elems += (((char *)reply)[x] == 0);
481 }
482 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
483 XENPCI_POOL_TAG);
484 for (x = i = 0; i < nr_elems; i++)
485 {
486 int l = (int)strlen((char *)reply + x);
487 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
488 memcpy(res[i], (char *)reply + x, l + 1);
489 x += l + 1;
490 }
491 res[i] = NULL;
492 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
493 *contents = res;
495 return NULL;
496 }
498 /* Called at PASSIVE_LEVEL */
499 static char *
500 XenBus_SendAddWatch(
501 PVOID Context,
502 xenbus_transaction_t xbt,
503 char *Path,
504 int slot)
505 {
506 PXENPCI_DEVICE_DATA xpdd = Context;
507 struct xsd_sockmsg *rep;
508 char *msg;
509 char Token[20];
510 struct write_req req[2];
512 req[0].data = Path;
513 req[0].len = (ULONG)strlen(Path) + 1;
515 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
516 req[1].data = Token;
517 req[1].len = (ULONG)strlen(Token) + 1;
519 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
521 msg = errmsg(rep);
522 if (!msg)
523 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
525 return msg;
526 }
528 /* called at PASSIVE_LEVEL */
529 NTSTATUS
530 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
531 {
532 int i;
534 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
535 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
536 if (xpdd->XenBus_WatchEntries[i].Active)
537 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
538 }
539 XenBus_Disconnect(xpdd);
541 return STATUS_SUCCESS;
542 }
544 /* called at PASSIVE_LEVEL */
545 NTSTATUS
546 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
547 {
548 NTSTATUS status;
549 int i;
551 FUNCTION_ENTER();
553 status = XenBus_Connect(xpdd);
554 if (!NT_SUCCESS(status))
555 {
556 return status;
557 }
559 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
560 {
561 if (xpdd->XenBus_WatchEntries[i].Active)
562 {
563 //KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
564 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
565 }
566 }
567 FUNCTION_EXIT();
569 return STATUS_SUCCESS;
570 }
572 char *
573 XenBus_AddWatch(
574 PVOID Context,
575 xenbus_transaction_t xbt,
576 char *Path,
577 PXENBUS_WATCH_CALLBACK ServiceRoutine,
578 PVOID ServiceContext)
579 {
580 PXENPCI_DEVICE_DATA xpdd = Context;
581 char *msg;
582 int i;
583 PXENBUS_WATCH_ENTRY w_entry;
585 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
587 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
589 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
591 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
592 if (xpdd->XenBus_WatchEntries[i].Active == 0)
593 break;
595 if (i == MAX_WATCH_ENTRIES)
596 {
597 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
598 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
599 return NULL;
600 }
602 /* must init watchentry before starting watch */
604 w_entry = &xpdd->XenBus_WatchEntries[i];
605 strncpy(w_entry->Path, Path, ARRAY_SIZE(w_entry->Path));
606 w_entry->ServiceRoutine = ServiceRoutine;
607 w_entry->ServiceContext = ServiceContext;
608 w_entry->Count = 0;
609 w_entry->Active = 1;
611 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
613 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
615 if (msg)
616 {
617 xpdd->XenBus_WatchEntries[i].Active = 0;
618 return msg;
619 }
621 return NULL;
622 }
624 char *
625 XenBus_RemWatch(
626 PVOID Context,
627 xenbus_transaction_t xbt,
628 char *Path,
629 PXENBUS_WATCH_CALLBACK ServiceRoutine,
630 PVOID ServiceContext)
631 {
632 PXENPCI_DEVICE_DATA xpdd = Context;
633 char *msg;
634 int i;
636 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
638 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
640 // check that Path < 128 chars
642 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
643 {
644 if (xpdd->XenBus_WatchEntries[i].Active
645 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)
646 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
647 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
648 {
649 KdPrint((__DRIVER_NAME " Match\n"));
650 break;
651 }
652 }
654 if (i == MAX_WATCH_ENTRIES)
655 {
656 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
657 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
658 return NULL;
659 }
661 xpdd->XenBus_WatchEntries[i].Active = 0;
662 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
664 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
666 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
668 return msg;
669 }
671 char *
672 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
673 {
674 PXENPCI_DEVICE_DATA xpdd = Context;
675 /* xenstored becomes angry if you send a length 0 message, so just
676 shove a nul terminator on the end */
677 struct write_req req = { "", 1};
678 struct xsd_sockmsg *rep;
679 char *err;
681 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
683 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
684 err = errmsg(rep);
685 if (err)
686 return err;
687 *xbt = atoi((char *)(rep + 1));
688 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
690 return NULL;
691 }
693 char *
694 XenBus_EndTransaction(
695 PVOID Context,
696 xenbus_transaction_t t,
697 int abort,
698 int *retry)
699 {
700 PXENPCI_DEVICE_DATA xpdd = Context;
701 struct xsd_sockmsg *rep;
702 struct write_req req;
703 char *err;
705 *retry = 0;
707 req.data = abort ? "F" : "T";
708 req.len = 2;
709 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
710 err = errmsg(rep);
711 if (err) {
712 if (!strcmp(err, "EAGAIN")) {
713 *retry = 1;
714 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
715 return NULL;
716 } else {
717 return err;
718 }
719 }
720 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
722 return NULL;
723 }
725 char *
726 XenBus_Printf(
727 PVOID Context,
728 xenbus_transaction_t xbt,
729 char *path,
730 char *fmt,
731 ...)
732 {
733 PXENPCI_DEVICE_DATA xpdd = Context;
734 va_list ap;
735 char buf[512];
736 char *retval;
738 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
740 va_start(ap, fmt);
741 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
742 va_end(ap);
743 retval = XenBus_Write(xpdd, xbt, path, buf);
745 return retval;
746 }