win-pvdrivers

view xenpci/xenbus.c @ 790:467005e7f509

Big messy changes. Add grant ref tagging to better track when things go wrong (debug build only).
Fix a race in xennet that causes crashes under heavy traffic conditions on driver shutdown.
author James Harper <james.harper@bendigoit.com.au>
date Fri Mar 12 09:38:42 2010 +1100 (2010-03-12)
parents 5bdb7251370c
children bbc6c94b9621
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 /* Not really necessary but keeps PREfast happy */
27 static EVT_WDF_WORKITEM XenBus_WatchWorkItemProc;
29 WDF_DECLARE_CONTEXT_TYPE(xsd_sockmsg_t)
31 struct write_req {
32 void *data;
33 unsigned len;
34 };
36 // This routine free's the rep structure if there was an error!!!
37 static char *errmsg(struct xsd_sockmsg *rep)
38 {
39 char *res;
41 if (!rep) {
42 char msg[] = "No reply";
43 size_t len = strlen(msg) + 1;
44 return memcpy(ExAllocatePoolWithTag(NonPagedPool, len, XENPCI_POOL_TAG), msg, len);
45 }
46 if (rep->type != XS_ERROR)
47 return NULL;
48 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
49 memcpy(res, rep + 1, rep->len);
50 res[rep->len] = 0;
51 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
52 return res;
53 }
55 static void memcpy_from_ring(void *Ring,
56 void *Dest,
57 int off,
58 int len)
59 {
60 int c1, c2;
61 char *ring = Ring;
62 char *dest = Dest;
63 c1 = min(len, XENSTORE_RING_SIZE - off);
64 c2 = len - c1;
65 memcpy(dest, ring + off, c1);
66 memcpy(dest + c1, ring, c2);
67 }
69 /* called with xenbus_mutex held */
70 static void xb_write(
71 PXENPCI_DEVICE_DATA xpdd,
72 PVOID data,
73 ULONG len
74 )
75 {
76 XENSTORE_RING_IDX prod;
77 ULONG copy_len;
78 PUCHAR ptr;
79 ULONG remaining;
81 //FUNCTION_ENTER();
83 ASSERT(len <= XENSTORE_RING_SIZE);
84 prod = xpdd->xen_store_interface->req_prod;
85 ptr = data;
86 remaining = len;
87 while (remaining)
88 {
89 copy_len = min(remaining, XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod));
90 memcpy((PUCHAR)xpdd->xen_store_interface->req + MASK_XENSTORE_IDX(prod), ptr, copy_len);
91 prod += (XENSTORE_RING_IDX)copy_len;
92 ptr += copy_len;
93 remaining -= copy_len;
94 }
95 /* Remote must see entire message before updating indexes */
96 KeMemoryBarrier();
97 xpdd->xen_store_interface->req_prod = prod;
98 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn);
100 //FUNCTION_EXIT();
101 }
103 /* takes and releases xb_request_mutex */
104 static struct xsd_sockmsg *
105 xenbus_format_msg_reply(
106 PXENPCI_DEVICE_DATA xpdd,
107 int type,
108 xenbus_transaction_t trans_id,
109 struct write_req *req,
110 int nr_reqs)
111 {
112 struct xsd_sockmsg msg;
113 struct xsd_sockmsg *reply;
114 int i;
116 //FUNCTION_ENTER();
118 msg.type = type;
119 msg.req_id = 0;
120 msg.tx_id = trans_id;
121 msg.len = 0;
122 for (i = 0; i < nr_reqs; i++)
123 msg.len += req[i].len;
125 ExAcquireFastMutex(&xpdd->xb_request_mutex);
126 xb_write(xpdd, &msg, sizeof(msg));
127 for (i = 0; i < nr_reqs; i++)
128 xb_write(xpdd, req[i].data, req[i].len);
130 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
131 reply = xpdd->xb_reply;
132 xpdd->xb_reply = NULL;
133 ExReleaseFastMutex(&xpdd->xb_request_mutex);
135 //FUNCTION_EXIT();
137 return reply;
138 }
140 /* takes and releases xb_request_mutex */
141 struct xsd_sockmsg *
142 XenBus_Raw(
143 PXENPCI_DEVICE_DATA xpdd,
144 struct xsd_sockmsg *msg)
145 {
146 struct xsd_sockmsg *reply;
148 //FUNCTION_ENTER();
150 ExAcquireFastMutex(&xpdd->xb_request_mutex);
151 xb_write(xpdd, msg, sizeof(struct xsd_sockmsg) + msg->len);
152 KeWaitForSingleObject(&xpdd->xb_request_complete_event, Executive, KernelMode, FALSE, NULL);
153 reply = xpdd->xb_reply;
154 xpdd->xb_reply = NULL;
155 ExReleaseFastMutex(&xpdd->xb_request_mutex);
157 //FUNCTION_EXIT();
159 return reply;
160 }
162 /* Called at PASSIVE_LEVEL */
163 char *
164 XenBus_Read(
165 PVOID Context,
166 xenbus_transaction_t xbt,
167 char *path,
168 char **value)
169 {
170 PXENPCI_DEVICE_DATA xpdd = Context;
171 struct write_req req[] = { {path, (ULONG)strlen(path) + 1} };
172 struct xsd_sockmsg *rep;
173 char *res;
174 char *msg;
176 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
178 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
180 rep = xenbus_format_msg_reply(xpdd, XS_READ, xbt, req, ARRAY_SIZE(req));
181 msg = errmsg(rep);
182 if (msg) {
183 *value = NULL;
184 return msg;
185 }
186 res = ExAllocatePoolWithTag(NonPagedPool, rep->len + 1, XENPCI_POOL_TAG);
187 memcpy(res, rep + 1, rep->len);
188 res[rep->len] = 0;
189 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
190 *value = res;
192 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
194 return NULL;
195 }
197 /* Called at PASSIVE_LEVEL */
198 char *
199 XenBus_Write(
200 PVOID Context,
201 xenbus_transaction_t xbt,
202 char *path,
203 char *value)
204 {
205 PXENPCI_DEVICE_DATA xpdd = Context;
206 struct write_req req[] = {
207 {path, (ULONG)strlen(path) + 1},
208 {value, (ULONG)strlen(value)},
209 };
210 struct xsd_sockmsg *rep;
211 char *msg;
213 //KdPrint((__DRIVER_NAME " --> " __FUNCTION__ "\n"));
215 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
217 rep = xenbus_format_msg_reply(xpdd, XS_WRITE, xbt, req, ARRAY_SIZE(req));
218 msg = errmsg(rep);
219 if (msg)
220 return msg;
221 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
223 //KdPrint((__DRIVER_NAME " <-- " __FUNCTION__ "\n"));
225 return NULL;
226 }
228 /* Called at PASSIVE_LEVEL */
229 static VOID
230 XenBus_WatchWorkItemProc(WDFWORKITEM workitem)
231 {
232 WDFDEVICE device = WdfWorkItemGetParentObject(workitem);
233 PXENPCI_DEVICE_DATA xpdd = GetXpdd(device);
234 xsd_sockmsg_t *msg;
235 PCHAR path;
236 int index;
237 PXENBUS_WATCH_ENTRY entry;
238 PXENBUS_WATCH_CALLBACK service_routine;
239 PVOID service_context;
241 //FUNCTION_ENTER();
242 msg = WdfObjectGetTypedContext(workitem, xsd_sockmsg_t);
243 path = (PCHAR)msg + sizeof(xsd_sockmsg_t);
244 index = atoi(path + strlen(path) + 1);
245 if (index < 0 || index >= MAX_WATCH_ENTRIES)
246 {
247 KdPrint((__DRIVER_NAME " Watch index %d out of range\n", index));
248 WdfObjectDelete(workitem);
249 //FUNCTION_ENTER();
250 return;
251 }
252 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
253 entry = &xpdd->XenBus_WatchEntries[index];
254 if (!entry->Active || !entry->ServiceRoutine)
255 {
256 KdPrint((__DRIVER_NAME " No watch for index %d\n", index));
257 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
258 WdfObjectDelete(workitem);
259 //FUNCTION_ENTER();
260 return;
261 }
262 entry->Count++;
263 service_routine = entry->ServiceRoutine;
264 service_context = entry->ServiceContext;
265 service_routine(path, service_context);
266 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
267 WdfObjectDelete(workitem);
268 //FUNCTION_EXIT();
269 }
271 /* Called at DISPATCH_LEVEL */
272 static VOID
273 XenBus_Dpc(PVOID ServiceContext)
274 {
275 NTSTATUS status;
276 PXENPCI_DEVICE_DATA xpdd = ServiceContext;
277 xsd_sockmsg_t msg;
278 ULONG msg_len;
279 WDF_WORKITEM_CONFIG workitem_config;
280 WDF_OBJECT_ATTRIBUTES workitem_attributes;
281 WDFWORKITEM workitem;
283 //FUNCTION_ENTER();
285 KeAcquireSpinLockAtDpcLevel(&xpdd->xb_ring_spinlock);
287 while (xpdd->xen_store_interface->rsp_prod != xpdd->xen_store_interface->rsp_cons)
288 {
289 if (!xpdd->xb_msg)
290 {
291 if (xpdd->xen_store_interface->rsp_prod - xpdd->xen_store_interface->rsp_cons < sizeof(xsd_sockmsg_t))
292 {
293 //KdPrint((__DRIVER_NAME " +++ Message incomplete (not even a full header)\n"));
294 break;
295 }
296 KeMemoryBarrier();
297 memcpy_from_ring(xpdd->xen_store_interface->rsp, &msg,
298 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons), sizeof(xsd_sockmsg_t));
299 xpdd->xb_msg = ExAllocatePoolWithTag(NonPagedPool, sizeof(xsd_sockmsg_t) + msg.len, XENPCI_POOL_TAG);
300 memcpy(xpdd->xb_msg, &msg, sizeof(xsd_sockmsg_t));
301 xpdd->xb_msg_offset = sizeof(xsd_sockmsg_t);
302 xpdd->xen_store_interface->rsp_cons += sizeof(xsd_sockmsg_t);
303 }
305 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);
306 KeMemoryBarrier(); /* make sure the data in the ring is valid */
307 ASSERT(xpdd->xb_msg_offset + msg_len <= sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len);
308 memcpy_from_ring(xpdd->xen_store_interface->rsp,
309 (PUCHAR)xpdd->xb_msg + xpdd->xb_msg_offset,
310 MASK_XENSTORE_IDX(xpdd->xen_store_interface->rsp_cons),
311 msg_len);
312 xpdd->xen_store_interface->rsp_cons += msg_len;
313 xpdd->xb_msg_offset += msg_len;
315 if (xpdd->xb_msg_offset < sizeof(xsd_sockmsg_t) + xpdd->xb_msg->len)
316 {
317 //KdPrint((__DRIVER_NAME " +++ Message incomplete (header but not full body)\n"));
318 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn); /* there is room on the ring now */
319 break;
320 }
322 if (xpdd->xb_msg->type != XS_WATCH_EVENT)
323 {
324 /* process reply - only ever one outstanding */
325 ASSERT(xpdd->xb_reply == NULL);
326 xpdd->xb_reply = xpdd->xb_msg;
327 xpdd->xb_msg = NULL;
328 KeSetEvent(&xpdd->xb_request_complete_event, IO_NO_INCREMENT, FALSE);
329 }
330 else
331 {
332 /* process watch */
333 WDF_WORKITEM_CONFIG_INIT(&workitem_config, XenBus_WatchWorkItemProc);
334 WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&workitem_attributes, xsd_sockmsg_t);
335 workitem_attributes.ParentObject = xpdd->wdf_device;
336 workitem_attributes.ContextSizeOverride = xpdd->xb_msg_offset;
337 status = WdfWorkItemCreate(&workitem_config, &workitem_attributes, &workitem);
338 if (!NT_SUCCESS(status))
339 {
340 KdPrint((__DRIVER_NAME " Failed to create work item for watch\n"));
341 continue;
342 }
343 memcpy(WdfObjectGetTypedContext(workitem, xsd_sockmsg_t), xpdd->xb_msg, xpdd->xb_msg_offset);
344 xpdd->xb_msg = NULL;
345 WdfWorkItemEnqueue(workitem);
346 }
347 EvtChn_Notify(xpdd, xpdd->xen_store_evtchn); /* there is room on the ring now */
348 }
349 KeReleaseSpinLockFromDpcLevel(&xpdd->xb_ring_spinlock);
351 //FUNCTION_EXIT();
352 }
354 static NTSTATUS
355 XenBus_Connect(PXENPCI_DEVICE_DATA xpdd)
356 {
357 PHYSICAL_ADDRESS pa_xen_store_interface;
358 xen_ulong_t xen_store_mfn;
360 xpdd->xen_store_evtchn = (evtchn_port_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_EVTCHN);
361 xen_store_mfn = (xen_ulong_t)hvm_get_parameter(xpdd, HVM_PARAM_STORE_PFN);
362 pa_xen_store_interface.QuadPart = (ULONGLONG)xen_store_mfn << PAGE_SHIFT;
363 xpdd->xen_store_interface = MmMapIoSpace(pa_xen_store_interface, PAGE_SIZE, MmNonCached);
365 EvtChn_BindDpc(xpdd, xpdd->xen_store_evtchn, XenBus_Dpc, xpdd);
367 return STATUS_SUCCESS;
368 }
370 static NTSTATUS
371 XenBus_Disconnect(PXENPCI_DEVICE_DATA xpdd)
372 {
373 EvtChn_Unbind(xpdd, xpdd->xen_store_evtchn);
375 MmUnmapIoSpace(xpdd->xen_store_interface, PAGE_SIZE);
377 return STATUS_SUCCESS;
378 }
380 NTSTATUS
381 XenBus_Init(PXENPCI_DEVICE_DATA xpdd)
382 {
383 NTSTATUS status;
384 int i;
386 FUNCTION_ENTER();
388 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
390 KeInitializeSpinLock(&xpdd->xb_ring_spinlock);
391 ExInitializeFastMutex(&xpdd->xb_request_mutex);
392 ExInitializeFastMutex(&xpdd->xb_watch_mutex);
394 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
395 {
396 xpdd->XenBus_WatchEntries[i].Active = 0;
397 }
399 KeInitializeEvent(&xpdd->xb_request_complete_event, SynchronizationEvent, FALSE);
401 status = XenBus_Connect(xpdd);
402 if (!NT_SUCCESS(status))
403 {
404 FUNCTION_EXIT();
405 return status;
406 }
408 FUNCTION_EXIT();
410 return STATUS_SUCCESS;
411 }
413 char *
414 XenBus_SendRemWatch(
415 PVOID context,
416 xenbus_transaction_t xbt,
417 char *path,
418 int index)
419 {
420 struct xsd_sockmsg *rep;
421 char *msg;
422 char Token[20];
423 struct write_req req[2];
425 req[0].data = path;
426 req[0].len = (ULONG)strlen(path) + 1;
428 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", index);
429 req[1].data = Token;
430 req[1].len = (ULONG)strlen(Token) + 1;
432 rep = xenbus_format_msg_reply(context, XS_UNWATCH, xbt, req, ARRAY_SIZE(req));
434 msg = errmsg(rep);
435 if (msg)
436 return msg;
438 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
440 return NULL;
441 }
443 NTSTATUS
444 XenBus_Halt(PXENPCI_DEVICE_DATA xpdd)
445 {
446 int i;
448 FUNCTION_ENTER();
450 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
452 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
453 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
454 {
455 if (xpdd->XenBus_WatchEntries[i].Active)
456 {
457 xpdd->XenBus_WatchEntries[i].Active = 0;
458 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
459 }
460 }
462 XenBus_Disconnect(xpdd);
464 FUNCTION_EXIT();
466 return STATUS_SUCCESS;
467 }
469 char *
470 XenBus_List(
471 PVOID Context,
472 xenbus_transaction_t xbt,
473 char *pre,
474 char ***contents)
475 {
476 PXENPCI_DEVICE_DATA xpdd = Context;
477 struct xsd_sockmsg *reply, *repmsg;
478 struct write_req req[] = { { pre, (ULONG)strlen(pre)+1 } };
479 ULONG nr_elems, x, i;
480 char **res;
481 char *msg;
483 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
485 repmsg = xenbus_format_msg_reply(xpdd, XS_DIRECTORY, xbt, req, ARRAY_SIZE(req));
486 msg = errmsg(repmsg);
487 if (msg)
488 {
489 *contents = NULL;
490 return msg;
491 }
492 reply = repmsg + 1;
493 for (x = nr_elems = 0; x < repmsg->len; x++)
494 {
495 nr_elems += (((char *)reply)[x] == 0);
496 }
497 res = ExAllocatePoolWithTag(NonPagedPool, sizeof(res[0]) * (nr_elems + 1),
498 XENPCI_POOL_TAG);
499 for (x = i = 0; i < nr_elems; i++)
500 {
501 int l = (int)strlen((char *)reply + x);
502 res[i] = ExAllocatePoolWithTag(NonPagedPool, l + 1, XENPCI_POOL_TAG);
503 memcpy(res[i], (char *)reply + x, l + 1);
504 x += l + 1;
505 }
506 res[i] = NULL;
507 ExFreePoolWithTag(repmsg, XENPCI_POOL_TAG);
508 *contents = res;
510 return NULL;
511 }
513 /* Called at PASSIVE_LEVEL */
514 static char *
515 XenBus_SendAddWatch(
516 PVOID Context,
517 xenbus_transaction_t xbt,
518 char *Path,
519 int slot)
520 {
521 PXENPCI_DEVICE_DATA xpdd = Context;
522 struct xsd_sockmsg *rep;
523 char *msg;
524 char Token[20];
525 struct write_req req[2];
527 req[0].data = Path;
528 req[0].len = (ULONG)strlen(Path) + 1;
530 RtlStringCbPrintfA(Token, ARRAY_SIZE(Token), "%d", slot);
531 req[1].data = Token;
532 req[1].len = (ULONG)strlen(Token) + 1;
534 rep = xenbus_format_msg_reply(xpdd, XS_WATCH, xbt, req, ARRAY_SIZE(req));
536 msg = errmsg(rep);
537 if (!msg)
538 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
540 return msg;
541 }
543 /* called at PASSIVE_LEVEL */
544 NTSTATUS
545 XenBus_Suspend(PXENPCI_DEVICE_DATA xpdd)
546 {
547 int i;
549 /* we need to remove the watches as a watch firing could lead to a XenBus_Read/Write/Printf */
550 for (i = 0; i < MAX_WATCH_ENTRIES; i++) {
551 if (xpdd->XenBus_WatchEntries[i].Active)
552 XenBus_SendRemWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
553 }
554 XenBus_Disconnect(xpdd);
556 return STATUS_SUCCESS;
557 }
559 /* called at PASSIVE_LEVEL */
560 NTSTATUS
561 XenBus_Resume(PXENPCI_DEVICE_DATA xpdd)
562 {
563 NTSTATUS status;
564 int i;
566 FUNCTION_ENTER();
568 status = XenBus_Connect(xpdd);
569 if (!NT_SUCCESS(status))
570 {
571 return status;
572 }
574 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
575 {
576 if (xpdd->XenBus_WatchEntries[i].Active)
577 {
578 //KdPrint((__DRIVER_NAME " Adding watch for path = %s\n", xpdd->XenBus_WatchEntries[i].Path));
579 XenBus_SendAddWatch(xpdd, XBT_NIL, xpdd->XenBus_WatchEntries[i].Path, i);
580 }
581 }
582 FUNCTION_EXIT();
584 return STATUS_SUCCESS;
585 }
587 char *
588 XenBus_AddWatch(
589 PVOID Context,
590 xenbus_transaction_t xbt,
591 char *Path,
592 PXENBUS_WATCH_CALLBACK ServiceRoutine,
593 PVOID ServiceContext)
594 {
595 PXENPCI_DEVICE_DATA xpdd = Context;
596 char *msg;
597 int i;
598 PXENBUS_WATCH_ENTRY w_entry;
600 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
602 ASSERT(strlen(Path) < ARRAY_SIZE(w_entry->Path));
604 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
606 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
607 if (xpdd->XenBus_WatchEntries[i].Active == 0)
608 break;
610 if (i == MAX_WATCH_ENTRIES)
611 {
612 KdPrint((__DRIVER_NAME " +++ No more watch slots left\n"));
613 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
614 return NULL;
615 }
617 /* must init watchentry before starting watch */
619 w_entry = &xpdd->XenBus_WatchEntries[i];
620 RtlStringCbCopyA(w_entry->Path, ARRAY_SIZE(w_entry->Path), Path);
621 w_entry->ServiceRoutine = ServiceRoutine;
622 w_entry->ServiceContext = ServiceContext;
623 w_entry->Count = 0;
624 w_entry->Active = 1;
626 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
628 msg = XenBus_SendAddWatch(xpdd, xbt, Path, i);
630 if (msg)
631 {
632 xpdd->XenBus_WatchEntries[i].Active = 0;
633 return msg;
634 }
636 return NULL;
637 }
639 char *
640 XenBus_RemWatch(
641 PVOID Context,
642 xenbus_transaction_t xbt,
643 char *Path,
644 PXENBUS_WATCH_CALLBACK ServiceRoutine,
645 PVOID ServiceContext)
646 {
647 PXENPCI_DEVICE_DATA xpdd = Context;
648 char *msg;
649 int i;
651 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
653 ExAcquireFastMutex(&xpdd->xb_watch_mutex);
655 // check that Path < 128 chars
657 for (i = 0; i < MAX_WATCH_ENTRIES; i++)
658 {
659 if (xpdd->XenBus_WatchEntries[i].Active
660 && !strcmp(xpdd->XenBus_WatchEntries[i].Path, Path)
661 && xpdd->XenBus_WatchEntries[i].ServiceRoutine == ServiceRoutine
662 && xpdd->XenBus_WatchEntries[i].ServiceContext == ServiceContext)
663 {
664 KdPrint((__DRIVER_NAME " Match\n"));
665 break;
666 }
667 }
669 if (i == MAX_WATCH_ENTRIES)
670 {
671 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
672 KdPrint((__DRIVER_NAME " Watch not set - can't remove\n"));
673 return NULL;
674 }
676 xpdd->XenBus_WatchEntries[i].Active = 0;
677 xpdd->XenBus_WatchEntries[i].Path[0] = 0;
679 ExReleaseFastMutex(&xpdd->xb_watch_mutex);
681 msg = XenBus_SendRemWatch(Context, xbt, Path, i);
683 return msg;
684 }
686 char *
687 XenBus_StartTransaction(PVOID Context, xenbus_transaction_t *xbt)
688 {
689 PXENPCI_DEVICE_DATA xpdd = Context;
690 /* xenstored becomes angry if you send a length 0 message, so just
691 shove a nul terminator on the end */
692 struct write_req req = { "", 1};
693 struct xsd_sockmsg *rep;
694 char *err;
696 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
698 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_START, 0, &req, 1);
699 err = errmsg(rep);
700 if (err)
701 return err;
702 *xbt = atoi((char *)(rep + 1));
703 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
705 return NULL;
706 }
708 char *
709 XenBus_EndTransaction(
710 PVOID Context,
711 xenbus_transaction_t t,
712 int abort,
713 int *retry)
714 {
715 PXENPCI_DEVICE_DATA xpdd = Context;
716 struct xsd_sockmsg *rep;
717 struct write_req req;
718 char *err;
720 *retry = 0;
722 req.data = abort ? "F" : "T";
723 req.len = 2;
724 rep = xenbus_format_msg_reply(xpdd, XS_TRANSACTION_END, t, &req, 1);
725 err = errmsg(rep);
726 if (err) {
727 if (!strcmp(err, "EAGAIN")) {
728 *retry = 1;
729 ExFreePoolWithTag(err, XENPCI_POOL_TAG);
730 return NULL;
731 } else {
732 return err;
733 }
734 }
735 ExFreePoolWithTag(rep, XENPCI_POOL_TAG);
737 return NULL;
738 }
740 char *
741 XenBus_Printf(
742 PVOID Context,
743 xenbus_transaction_t xbt,
744 char *path,
745 char *fmt,
746 ...)
747 {
748 PXENPCI_DEVICE_DATA xpdd = Context;
749 va_list ap;
750 char buf[512];
751 char *retval;
753 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
755 va_start(ap, fmt);
756 RtlStringCbVPrintfA(buf, ARRAY_SIZE(buf), fmt, ap);
757 va_end(ap);
758 retval = XenBus_Write(xpdd, xbt, path, buf);
760 return retval;
761 }