win-pvdrivers

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