~n-muench/ubuntu/oneiric/open-vm-tools/open-vm-tools.fix-836277

« back to all changes in this revision

Viewing changes to modules/linux/vmci/vmciDatagram.c

  • Committer: Evan Broder
  • Date: 2010-03-21 23:26:53 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: broder@mit.edu-20100321232653-5a57r7v7ch4o6byv
Merging shared upstream rev into target branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
56
56
 
57
57
   VMCIHandle                handle;
58
58
   uint32                    flags;
 
59
   Bool                      runDelayed;
59
60
   VMCIDatagramRecvCB        recvCB;
60
61
   void                      *clientData;
61
62
   VMCIEvent                 destroyEvent;
63
64
 
64
65
#define HASH_TABLE_SIZE 64
65
66
 
 
67
#define VMCI_HASHRESOURCE(handle, size)                              \
 
68
   VMCI_HashId(VMCI_HANDLE_TO_RESOURCE_ID(handle), (size))
 
69
 
66
70
/* 
67
71
 * Hash table containing all the datagram handles for this VM. It is 
68
72
 * synchronized using a single lock but we should consider making it more
72
76
typedef struct DatagramHashTable {
73
77
   VMCILock lock;
74
78
   DatagramHashEntry *entries[HASH_TABLE_SIZE];
75
 
} DatagramHashTable; 
 
79
} DatagramHashTable;
 
80
 
 
81
typedef struct VMCIDelayedDatagramInfo {
 
82
   DatagramHashEntry *entry;
 
83
   VMCIDatagram msg;
 
84
} VMCIDelayedDatagramInfo;
76
85
 
77
86
 
78
87
static int DatagramReleaseCB(void *clientData);
79
88
static int DatagramHashAddEntry(DatagramHashEntry *entry, VMCIId contextID);
80
89
static int DatagramHashRemoveEntry(VMCIHandle handle);
81
90
static DatagramHashEntry *DatagramHashGetEntry(VMCIHandle handle);
 
91
static DatagramHashEntry *DatagramHashGetEntryAnyCid(VMCIHandle handle);
82
92
static void DatagramHashReleaseEntry(DatagramHashEntry *entry);
83
 
static Bool DatagramHandleUniqueLocked(VMCIHandle handle);
 
93
static Bool DatagramHandleUniqueLockedAnyCid(VMCIHandle handle);
84
94
static int DatagramProcessNotify(void *clientData, VMCIDatagram *msg);
85
95
 
86
96
DatagramHashTable hashTable;
133
143
   VMCILockFlags flags;
134
144
   static VMCIId datagramRID = VMCI_RESERVED_RESOURCE_ID_MAX + 1;
135
145
 
136
 
   ASSERT(entry && contextID != VMCI_INVALID_ID);
 
146
   ASSERT(entry);
137
147
 
138
148
   VMCI_GrabLock_BH(&hashTable.lock, &flags);
139
149
   if (!VMCI_HANDLE_INVALID(entry->handle) &&
140
 
       !DatagramHandleUniqueLocked(entry->handle)) {
 
150
       !DatagramHandleUniqueLockedAnyCid(entry->handle)) {
141
151
      VMCI_ReleaseLock_BH(&hashTable.lock, flags);
142
152
      return VMCI_ERROR_DUPLICATE_ENTRY;
143
153
   } else if (VMCI_HANDLE_INVALID(entry->handle)) {
152
162
      ASSERT(oldRID > VMCI_RESERVED_RESOURCE_ID_MAX);
153
163
      do {
154
164
         handle = VMCI_MAKE_HANDLE(contextID, datagramRID);
155
 
         foundRID = DatagramHandleUniqueLocked(handle);
 
165
         foundRID = DatagramHandleUniqueLockedAnyCid(handle);
156
166
         datagramRID++;
157
167
         if (UNLIKELY(!datagramRID)) {
158
168
            /*
175
185
   }
176
186
   
177
187
   ASSERT(!VMCI_HANDLE_INVALID(entry->handle));
178
 
   idx = VMCI_Hash(entry->handle, HASH_TABLE_SIZE);
 
188
   idx = VMCI_HASHRESOURCE(entry->handle, HASH_TABLE_SIZE);
179
189
 
180
190
   /* New entry is added to top/front of hash bucket. */
181
191
   entry->refCount++;
204
214
   int result = VMCI_ERROR_NOT_FOUND;
205
215
   VMCILockFlags flags;
206
216
   DatagramHashEntry *prev, *cur;
207
 
   int idx = VMCI_Hash(handle, HASH_TABLE_SIZE);
 
217
   int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE);
208
218
 
209
219
   prev = NULL;
210
220
   VMCI_GrabLock_BH(&hashTable.lock, &flags);
245
255
 *
246
256
 *  DatagramHashGetEntry --
247
257
 *
 
258
 *     Gets the given datagram hashtable entry based on handle lookup.
 
259
 *
248
260
 *  Result:
249
 
 *     None.
250
 
 *     
 
261
 *     Datagram hash entry if found. NULL otherwise.
 
262
 *
251
263
 *-------------------------------------------------------------------------
252
264
 */
253
265
 
254
266
static DatagramHashEntry *
255
 
DatagramHashGetEntry(VMCIHandle handle)
 
267
DatagramHashGetEntry(VMCIHandle handle) // IN
256
268
{
257
269
   VMCILockFlags flags;
258
270
   DatagramHashEntry *cur;
259
 
   int idx = VMCI_Hash(handle, HASH_TABLE_SIZE);
260
 
   
 
271
   int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE);
 
272
 
261
273
   VMCI_GrabLock_BH(&hashTable.lock, &flags);
 
274
 
262
275
   for (cur = hashTable.entries[idx]; cur != NULL; cur = cur->next) {
263
276
      if (VMCI_HANDLE_EQUAL(cur->handle, handle)) {
264
277
         cur->refCount++;
265
278
         break;
266
279
      }
267
280
   }
268
 
   VMCI_ReleaseLock_BH(&hashTable.lock, flags);
269
 
   
 
281
 
 
282
   VMCI_ReleaseLock_BH(&hashTable.lock, flags);
 
283
 
 
284
   return cur;
 
285
}
 
286
 
 
287
 
 
288
/*
 
289
 *-------------------------------------------------------------------------
 
290
 *
 
291
 *  DatagramHashGetEntryAnyCid --
 
292
 *
 
293
 *     Gets the given datagram hashtable entry based on handle lookup.
 
294
 *     Will match "any" or specific cid.
 
295
 *
 
296
 *  Result:
 
297
 *     Datagram hash entry if found. NULL otherwise.
 
298
 *
 
299
 *-------------------------------------------------------------------------
 
300
 */
 
301
 
 
302
static DatagramHashEntry *
 
303
DatagramHashGetEntryAnyCid(VMCIHandle handle) // IN
 
304
{
 
305
   VMCILockFlags flags;
 
306
   DatagramHashEntry *cur;
 
307
   int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE);
 
308
 
 
309
   VMCI_GrabLock_BH(&hashTable.lock, &flags);
 
310
 
 
311
   for (cur = hashTable.entries[idx]; cur != NULL; cur = cur->next) {
 
312
      if (VMCI_HANDLE_TO_RESOURCE_ID(cur->handle) ==
 
313
          VMCI_HANDLE_TO_RESOURCE_ID(handle)) {
 
314
         if (VMCI_HANDLE_TO_CONTEXT_ID(cur->handle) == VMCI_INVALID_ID ||
 
315
             VMCI_HANDLE_TO_CONTEXT_ID(cur->handle) ==
 
316
             VMCI_HANDLE_TO_CONTEXT_ID(handle)) {
 
317
            cur->refCount++;
 
318
            break;
 
319
         }
 
320
      }
 
321
   }
 
322
 
 
323
   VMCI_ReleaseLock_BH(&hashTable.lock, flags);
 
324
 
270
325
   return cur;
271
326
}
272
327
 
276
331
 *
277
332
 *  DatagramHashReleaseEntry --
278
333
 *
 
334
 *     Drops a reference to the current hash entry. If this is the last
 
335
 *     reference then the entry is freed.
 
336
 *
279
337
 *  Result:
280
338
 *     None.
281
 
 *     
 
339
 *
282
340
 *-------------------------------------------------------------------------
283
341
 */
284
342
 
285
343
static void
286
 
DatagramHashReleaseEntry(DatagramHashEntry *entry)
 
344
DatagramHashReleaseEntry(DatagramHashEntry *entry) // IN
287
345
{
288
346
   VMCILockFlags flags;
289
347
 
291
349
   entry->refCount--;
292
350
 
293
351
   /* Check if this is last reference and signal the destroy event if so. */
294
 
   if (entry->refCount == 0) { 
 
352
   if (entry->refCount == 0) {
295
353
      VMCI_SignalEvent(&entry->destroyEvent);
296
354
   }
297
355
   VMCI_ReleaseLock_BH(&hashTable.lock, flags);
301
359
/*
302
360
 *------------------------------------------------------------------------------
303
361
 *
304
 
 *  DatagramHandleUniqueLocked --
 
362
 *  DatagramHandleUniqueLockedAnyCid --
305
363
 *
306
 
 *     Checks whether the given handle is already in the hash
307
 
 *     table. Assumes that the caller to have the hash table lock.
 
364
 *     Checks whether the resource id (with any context id) is already in the
 
365
 *     hash table.
 
366
 *     Assumes that the caller has the hash table lock.
308
367
 *
309
368
 *  Result:
310
 
 *     None.
311
 
 *     
 
369
 *     TRUE if the handle is unique. FALSE otherwise.
 
370
 *
312
371
 *------------------------------------------------------------------------------
313
372
 */
314
373
 
315
374
static Bool
316
 
DatagramHandleUniqueLocked(VMCIHandle handle)
 
375
DatagramHandleUniqueLockedAnyCid(VMCIHandle handle) // IN
317
376
{
318
377
   Bool unique = TRUE;
319
378
   DatagramHashEntry *entry;
320
 
   int idx = VMCI_Hash(handle, HASH_TABLE_SIZE);
 
379
   int idx = VMCI_HASHRESOURCE(handle, HASH_TABLE_SIZE);
321
380
 
322
381
   entry = hashTable.entries[idx];
323
382
   while (entry) {
324
 
      if (VMCI_HANDLE_EQUAL(entry->handle, handle)) {
 
383
      if (VMCI_HANDLE_TO_RESOURCE_ID(entry->handle) ==
 
384
          VMCI_HANDLE_TO_RESOURCE_ID(handle)) {
325
385
         unique = FALSE;
326
386
         break;
327
387
      }
358
418
   int result;
359
419
   DatagramHashEntry *entry;
360
420
   VMCIHandle handle;
361
 
   VMCIId contextID = VMCI_GetContextID();
 
421
   VMCIId contextID;
362
422
 
363
423
   if (!recvCB || !outHandle) {
364
424
      return VMCI_ERROR_INVALID_ARGS;
365
425
   }
366
426
 
367
 
   /* Validate contextID. */
368
 
   if (contextID == VMCI_INVALID_ID) {
369
 
      return VMCI_ERROR_NO_RESOURCES;
 
427
   if ((flags & VMCI_FLAG_ANYCID_DG_HND) != 0) {
 
428
      contextID = VMCI_INVALID_ID;
 
429
   } else {
 
430
      contextID = VMCI_GetContextID();
 
431
      /* Validate contextID. */
 
432
      if (contextID == VMCI_INVALID_ID) {
 
433
         return VMCI_ERROR_NO_RESOURCES;
 
434
      }
370
435
   }
371
436
 
 
437
 
372
438
   if ((flags & VMCI_FLAG_WELLKNOWN_DG_HND) != 0) {
373
439
      VMCIDatagramWellKnownMapMsg wkMsg;
374
440
      if (resourceID == VMCI_INVALID_ID) {
375
 
         return VMCI_ERROR_INVALID_ARGS;
 
441
         return VMCI_ERROR_INVALID_ARGS;
376
442
      }
377
443
      wkMsg.hdr.dst.context = VMCI_HYPERVISOR_CONTEXT_ID;
378
444
      wkMsg.hdr.dst.resource = VMCI_DATAGRAM_REQUEST_MAP;
381
447
      wkMsg.wellKnownID = resourceID;
382
448
      result = VMCI_SendDatagram((VMCIDatagram *)&wkMsg);
383
449
      if (result < VMCI_SUCCESS) {
384
 
         VMCI_LOG(("Failed to reserve wellknown id %d, error %d.\n",
385
 
                   resourceID, result));
386
 
         return result;
 
450
         VMCI_LOG(("Failed to reserve wellknown id %d, error %d.\n",
 
451
                   resourceID, result));
 
452
         return result;
387
453
      }
388
454
 
389
455
      handle = VMCI_MAKE_HANDLE(VMCI_WELL_KNOWN_CONTEXT_ID, resourceID);
401
467
      return VMCI_ERROR_NO_MEM;
402
468
   }
403
469
 
 
470
   if (!VMCI_CanScheduleDelayedWork()) {
 
471
      if (flags & VMCI_FLAG_DG_DELAYED_CB) {
 
472
         VMCI_FreeKernelMem(entry, sizeof *entry);
 
473
         return VMCI_ERROR_INVALID_ARGS;
 
474
      }
 
475
      entry->runDelayed = FALSE;
 
476
   } else {
 
477
      entry->runDelayed = (flags & VMCI_FLAG_DG_DELAYED_CB) ? TRUE : FALSE;
 
478
   }
 
479
 
404
480
   entry->handle = handle;
405
481
   entry->flags = flags;
406
482
   entry->recvCB = recvCB;
622
698
#endif
623
699
 
624
700
int
625
 
VMCIDatagram_Send(VMCIDatagram *msg) // IN              
 
701
VMCIDatagram_Send(VMCIDatagram *msg) // IN
626
702
{
627
703
   uint32 retval;
628
704
   DatagramHashEntry *entry;
 
705
   VMCIId contextId;
629
706
 
630
707
   if (msg == NULL) {
631
708
      VMCI_LOG(("Invalid datagram.\n"));
640
717
   /* Check srcHandle exists otherwise fail. */
641
718
   entry = DatagramHashGetEntry(msg->src);
642
719
   if (entry == NULL) {
643
 
      VMCI_LOG(("Couldn't find handle 0x%x:0x%x.\n", 
 
720
      VMCI_LOG(("Couldn't find handle 0x%x:0x%x.\n",
644
721
                msg->src.context, msg->src.resource));
645
722
      return VMCI_ERROR_INVALID_ARGS;
646
723
   }
647
 
   
 
724
 
 
725
   contextId = VMCI_HANDLE_TO_CONTEXT_ID(msg->src);
 
726
 
 
727
   if (contextId == VMCI_INVALID_ID) {
 
728
      msg->src = VMCI_MAKE_HANDLE(VMCI_GetContextID(),
 
729
                                  VMCI_HANDLE_TO_RESOURCE_ID(msg->src));
 
730
   }
 
731
 
648
732
   retval = VMCI_SendDatagram(msg);
649
733
   DatagramHashReleaseEntry(entry);
650
734
 
655
739
/*
656
740
 *-----------------------------------------------------------------------------
657
741
 *
 
742
 * VMCIDatagramDelayedDispatchCB --
 
743
 *
 
744
 *      Calls the specified callback in a delayed context.
 
745
 *
 
746
 * Results:
 
747
 *      None.
 
748
 *
 
749
 * Side effects:
 
750
 *      None.
 
751
 *
 
752
 *-----------------------------------------------------------------------------
 
753
 */
 
754
 
 
755
static void
 
756
VMCIDatagramDelayedDispatchCB(void *data) // IN
 
757
{
 
758
   VMCIDelayedDatagramInfo *dgInfo = (VMCIDelayedDatagramInfo *)data;
 
759
 
 
760
   ASSERT(data);
 
761
 
 
762
   dgInfo->entry->recvCB(dgInfo->entry->clientData, &dgInfo->msg);
 
763
 
 
764
   DatagramHashReleaseEntry(dgInfo->entry);
 
765
   VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)dgInfo->msg.payloadSize);
 
766
}
 
767
 
 
768
 
 
769
/*
 
770
 *-----------------------------------------------------------------------------
 
771
 *
658
772
 * VMCIDatagram_Dispatch --
659
773
 *
660
 
 *      Forwards the datagram corresponding entry's callback.
 
774
 *      Forwards the datagram to the corresponding entry's callback.  This will
 
775
 *      defer the datagram if requested by the client, so that the callback
 
776
 *      is invoked in a delayed context.
661
777
 *
662
778
 * Results:
663
779
 *      VMCI_SUCCESS on success, error code if not.
670
786
 
671
787
int
672
788
VMCIDatagram_Dispatch(VMCIId contextID,  // IN: unused
673
 
                      VMCIDatagram *msg) // IN
 
789
                      VMCIDatagram *msg) // IN
674
790
{
 
791
   int32 err = VMCI_SUCCESS;
675
792
   DatagramHashEntry *entry;
676
 
   
 
793
 
677
794
   ASSERT(msg);
678
795
 
679
 
   entry = DatagramHashGetEntry(msg->dst);
 
796
   entry = DatagramHashGetEntryAnyCid(msg->dst);
680
797
   if (entry == NULL) {
681
 
      VMCI_LOG(("destination handle 0x%x:0x%x doesn't exists.\n",
 
798
      VMCI_LOG(("destination handle 0x%x:0x%x doesn't exist.\n",
682
799
                msg->dst.context, msg->dst.resource));
683
800
      return VMCI_ERROR_NO_HANDLE;
684
801
   }
685
 
   
686
 
   if (entry->recvCB) {
 
802
 
 
803
   if (!entry->recvCB) {
 
804
      VMCI_LOG(("no handle callback for handle 0x%x:0x%x payload of "
 
805
                "size %"FMT64"d.\n",
 
806
                msg->dst.context, msg->dst.resource, msg->payloadSize));
 
807
      goto out;
 
808
   }
 
809
 
 
810
   if (entry->runDelayed) {
 
811
      VMCIDelayedDatagramInfo *dgInfo;
 
812
 
 
813
      dgInfo = VMCI_AllocKernelMem(sizeof *dgInfo + (size_t)msg->payloadSize,
 
814
                                   VMCI_MEMORY_ATOMIC | VMCI_MEMORY_NONPAGED);
 
815
      if (NULL == dgInfo) {
 
816
         err = VMCI_ERROR_NO_MEM;
 
817
         goto out;
 
818
      }
 
819
 
 
820
      dgInfo->entry = entry;
 
821
      memcpy(&dgInfo->msg, msg, VMCI_DG_SIZE(msg));
 
822
 
 
823
      err = VMCI_ScheduleDelayedWork(VMCIDatagramDelayedDispatchCB, dgInfo);
 
824
      if (VMCI_SUCCESS == err) {
 
825
         return err;
 
826
      }
 
827
 
 
828
      VMCI_FreeKernelMem(dgInfo, sizeof *dgInfo + (size_t)msg->payloadSize);
 
829
   } else {
687
830
      entry->recvCB(entry->clientData, msg);
688
 
   } else {
689
 
      VMCI_LOG(("no handle callback for handle 0x%x:0x%x payload of "
690
 
                "size %"FMT64"d.\n", 
691
 
                msg->dst.context, msg->dst.resource, msg->payloadSize));
692
831
   }
 
832
 
 
833
out:
693
834
   DatagramHashReleaseEntry(entry);
694
 
 
695
 
   return VMCI_SUCCESS;
 
835
   return err;
696
836
}
697
837
 
698
838
 
852
992
 */
853
993
 
854
994
int
855
 
VMCIDatagramProcess_Create(VMCIDatagramProcess **outDgmProc,    // OUT:
856
 
                           VMCIDatagramCreateInfo *createInfo,  // IN:
857
 
                           uintptr_t eventHnd)                  // IN:
 
995
VMCIDatagramProcess_Create(VMCIDatagramProcess **outDgmProc,          // OUT:
 
996
                           VMCIDatagramCreateProcessInfo *createInfo, // IN:
 
997
                           uintptr_t eventHnd)                        // IN:
858
998
{
859
999
   VMCIDatagramProcess *dgmProc;
860
1000
 
877
1017
    * createInfo.
878
1018
    */
879
1019
   createInfo->result = VMCIDatagram_CreateHnd(createInfo->resourceID,
880
 
                                               createInfo->flags,
881
 
                                               DatagramProcessNotify,
882
 
                                               (void *)dgmProc,
883
 
                                               &dgmProc->handle);
 
1020
                                               createInfo->flags,
 
1021
                                               DatagramProcessNotify,
 
1022
                                               (void *)dgmProc,
 
1023
                                               &dgmProc->handle);
884
1024
   if (createInfo->result < VMCI_SUCCESS) {
885
1025
      VMCI_FreeKernelMem(dgmProc, sizeof *dgmProc);
886
1026
      return createInfo->result;