~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to modules/linux/vmci/common/vmciQPair.c

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2010 VMware, Inc. All rights reserved.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License as published by the
 
6
 * Free Software Foundation version 2 and no later version.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
10
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
11
 * for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along
 
14
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
15
 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
16
 *
 
17
 *********************************************************/
 
18
 
 
19
/*
 
20
 * vmciQPair.c --
 
21
 *
 
22
 *      This file implements Queue accessor methods.
 
23
 *
 
24
 *      VMCIQPair is a new interface that hides the queue pair internals.
 
25
 *      Rather than access each queue in a pair directly, operations are now
 
26
 *      performed on the queue as a whole.  This is simpler and less
 
27
 *      error-prone, and allows for future queue pair features to be added
 
28
 *      under the hood with no change to the client code.
 
29
 *
 
30
 *      This also helps in a particular case on Windows hosts, where the memory
 
31
 *      allocated by the client (e.g., VMX) will disappear when the client does
 
32
 *      (e.g., abnormal termination).  The kernel can't lock user memory into
 
33
 *      its address space indefinitely.  By guarding access to the queue
 
34
 *      contents we can correctly handle the case where the client disappears.
 
35
 *
 
36
 *      On code style:
 
37
 *
 
38
 *      + This entire file started its life as a cut-and-paste of the
 
39
 *        static INLINE functions in bora/public/vmci_queue_pair.h.
 
40
 *        From there, new copies of the routines were made named
 
41
 *        without the prefix VMCI, without the underscore (the one
 
42
 *        that followed VMCIQueue_).  The no-underscore versions of
 
43
 *        the routines require that the mutexes are held.
 
44
 *
 
45
 *      + The code -always- uses the xyzLocked() version of any given
 
46
 *        routine even when the wrapped function is a one-liner.  The
 
47
 *        reason for this decision was to ensure that we didn't have
 
48
 *        copies of logic lying around that needed to be maintained.
 
49
 *
 
50
 *      + Note that we still pass around 'const VMCIQueue *'s.
 
51
 *
 
52
 *      + Note that mutex is a field within VMCIQueue.  We skirt the
 
53
 *        issue of passing around a const VMCIQueue, even though the
 
54
 *        mutex field (__mutex, specifically) will get modified by not
 
55
 *        ever referring to the mutex -itself- except during
 
56
 *        initialization.  Beyond that, the code only passes the
 
57
 *        pointer to the mutex, which is also a member of VMCIQueue,
 
58
 *        obviously, and which doesn't change after initialization.
 
59
 *        This eliminates having to redefine all the functions that
 
60
 *        are currently taking const VMCIQueue's so that these
 
61
 *        functions are compatible with those definitions.
 
62
 */
 
63
 
 
64
#include "vmci_kernel_if.h"
 
65
#include "vm_assert.h"
 
66
#include "vmci_handle_array.h"
 
67
#include "vmci_defs.h"
 
68
#include "vmciKernelAPI.h"
 
69
#include "vmciQueuePair.h"
 
70
#include "vmciRoute.h"
 
71
 
 
72
/*
 
73
 * VMCIQPair
 
74
 *
 
75
 *      This structure is opaque to the clients.
 
76
 */
 
77
 
 
78
struct VMCIQPair {
 
79
   VMCIHandle handle;
 
80
   VMCIQueue *produceQ;
 
81
   VMCIQueue *consumeQ;
 
82
   uint64 produceQSize;
 
83
   uint64 consumeQSize;
 
84
   VMCIId peer;
 
85
   uint32 flags;
 
86
   VMCIPrivilegeFlags privFlags;
 
87
   Bool guestEndpoint;
 
88
};
 
89
 
 
90
#define VMCI_QPAIR_NO_QUEUE(_qp) (!(_qp)->produceQ->qHeader || \
 
91
                                  !(_qp)->consumeQ->qHeader)
 
92
 
 
93
 
 
94
/*
 
95
 *-----------------------------------------------------------------------------
 
96
 *
 
97
 * VMCIQPair_Alloc --
 
98
 *
 
99
 *      This is the client interface for allocating the memory for a
 
100
 *      VMCIQPair structure and then attaching to the underlying
 
101
 *      queue.  If an error occurs allocating the memory for the
 
102
 *      VMCIQPair structure, no attempt is made to attach.  If an
 
103
 *      error occurs attaching, then there's the VMCIQPair structure
 
104
 *      is freed.
 
105
 *
 
106
 * Results:
 
107
 *      An err, if < 0.
 
108
 *
 
109
 * Side effects:
 
110
 *      Windows blocking call.
 
111
 *
 
112
 *-----------------------------------------------------------------------------
 
113
 */
 
114
 
 
115
VMCI_EXPORT_SYMBOL(VMCIQPair_Alloc)
 
116
int
 
117
VMCIQPair_Alloc(VMCIQPair **qpair,            // OUT
 
118
                VMCIHandle *handle,           // OUT
 
119
                uint64 produceQSize,          // IN
 
120
                uint64 consumeQSize,          // IN
 
121
                VMCIId peer,                  // IN
 
122
                uint32 flags,                 // IN
 
123
                VMCIPrivilegeFlags privFlags) // IN
 
124
{
 
125
   VMCIQPair *myQPair;
 
126
   int retval;
 
127
   VMCIHandle src = VMCI_INVALID_HANDLE;
 
128
   VMCIHandle dst = VMCI_MAKE_HANDLE(peer, VMCI_INVALID_ID);
 
129
   VMCIRoute route;
 
130
 
 
131
   myQPair = VMCI_AllocKernelMem(sizeof *myQPair, VMCI_MEMORY_NONPAGED);
 
132
   if (!myQPair) {
 
133
      return VMCI_ERROR_NO_MEM;
 
134
   }
 
135
   memset(myQPair, 0, sizeof *myQPair);
 
136
 
 
137
   myQPair->produceQSize = produceQSize;
 
138
   myQPair->consumeQSize = consumeQSize;
 
139
   myQPair->peer = peer;
 
140
   myQPair->flags = flags;
 
141
   myQPair->privFlags = privFlags;
 
142
 
 
143
   retval = VMCI_Route(&src, &dst, FALSE, &route);
 
144
   if (retval < VMCI_SUCCESS) {
 
145
      if (VMCI_GuestPersonalityActive()) {
 
146
         route = VMCI_ROUTE_AS_GUEST;
 
147
      } else {
 
148
         route = VMCI_ROUTE_AS_HOST;
 
149
      }
 
150
   }
 
151
 
 
152
   if (VMCI_ROUTE_AS_HOST == route) {
 
153
      myQPair->guestEndpoint = FALSE;
 
154
   } else {
 
155
      myQPair->guestEndpoint = TRUE;
 
156
   }
 
157
 
 
158
   retval = VMCIQueuePair_Alloc(handle,
 
159
                                &myQPair->produceQ,
 
160
                                myQPair->produceQSize,
 
161
                                &myQPair->consumeQ,
 
162
                                myQPair->consumeQSize,
 
163
                                myQPair->peer,
 
164
                                myQPair->flags,
 
165
                                myQPair->privFlags,
 
166
                                myQPair->guestEndpoint);
 
167
 
 
168
   if (retval < VMCI_SUCCESS) {
 
169
      VMCI_FreeKernelMem(myQPair, sizeof *myQPair);
 
170
      return retval;
 
171
   }
 
172
 
 
173
   *qpair = myQPair;
 
174
   myQPair->handle = *handle;
 
175
 
 
176
   return retval;
 
177
}
 
178
 
 
179
 
 
180
/*
 
181
 *-----------------------------------------------------------------------------
 
182
 *
 
183
 * VMCIQPair_Detach --
 
184
 *
 
185
 *      This is the client interface for detaching from a VMCIQPair.
 
186
 *      Note that this routine will free the memory allocated for the
 
187
 *      VMCIQPair structure, too.
 
188
 *
 
189
 * Results:
 
190
 *      An error, if < 0.
 
191
 *
 
192
 * Side effects:
 
193
 *      Will clear the caller's pointer to the VMCIQPair structure.
 
194
 *
 
195
 *-----------------------------------------------------------------------------
 
196
 */
 
197
 
 
198
VMCI_EXPORT_SYMBOL(VMCIQPair_Detach)
 
199
int
 
200
VMCIQPair_Detach(VMCIQPair **qpair) // IN/OUT
 
201
{
 
202
   int result;
 
203
   VMCIQPair *oldQPair;
 
204
 
 
205
   if (!qpair || !(*qpair)) {
 
206
      return VMCI_ERROR_INVALID_ARGS;
 
207
   }
 
208
 
 
209
   oldQPair = *qpair;
 
210
   result = VMCIQueuePair_Detach(oldQPair->handle, oldQPair->guestEndpoint);
 
211
 
 
212
   if  (result >= VMCI_SUCCESS) {
 
213
#ifdef DEBUG
 
214
      oldQPair->handle = VMCI_INVALID_HANDLE;
 
215
      oldQPair->produceQ = NULL;
 
216
      oldQPair->consumeQ = NULL;
 
217
      oldQPair->produceQSize = 0;
 
218
      oldQPair->consumeQSize = 0;
 
219
      oldQPair->flags = 0;
 
220
      oldQPair->privFlags = 0;
 
221
      oldQPair->peer = VMCI_INVALID_ID;
 
222
#endif
 
223
 
 
224
      VMCI_FreeKernelMem(oldQPair, sizeof *oldQPair);
 
225
 
 
226
      *qpair = NULL;
 
227
   }
 
228
 
 
229
   return result;
 
230
}
 
231
 
 
232
 
 
233
/*
 
234
 * "Windows blocking call."
 
235
 *
 
236
 *      Note that on the Windows platform, kernel module clients may
 
237
 *      block when calling into any these rouintes.  The reason is
 
238
 *      that a mutex has to be acquired in order to view/modify the
 
239
 *      VMCIQueue structure fields: pointers, handle, and buffer data.
 
240
 *      However, other platforms don't require the acquisition of a
 
241
 *      mutex and thus don't block.
 
242
 */
 
243
 
 
244
 
 
245
/*
 
246
 *-----------------------------------------------------------------------------
 
247
 *
 
248
 * VMCIQPair_Lock --
 
249
 *
 
250
 *      Helper routine that will lock the QPair before subsequent operations.
 
251
 *
 
252
 * Results:
 
253
 *      None.
 
254
 *
 
255
 * Side effects:
 
256
 *      Windows blocking call.
 
257
 *
 
258
 *-----------------------------------------------------------------------------
 
259
 */
 
260
 
 
261
static INLINE void
 
262
VMCIQPairLock(const VMCIQPair *qpair) // IN
 
263
{
 
264
#if !defined VMX86_VMX
 
265
   VMCI_AcquireQueueMutex(qpair->produceQ);
 
266
#endif
 
267
}
 
268
 
 
269
 
 
270
/*
 
271
 *-----------------------------------------------------------------------------
 
272
 *
 
273
 * VMCIQPair_Unlock --
 
274
 *
 
275
 *      Helper routine that will unlock the QPair after various operations.
 
276
 *
 
277
 * Results:
 
278
 *      None.
 
279
 *
 
280
 * Side effects:
 
281
 *      None.
 
282
 *
 
283
 *-----------------------------------------------------------------------------
 
284
 */
 
285
 
 
286
static INLINE void
 
287
VMCIQPairUnlock(const VMCIQPair *qpair) // IN
 
288
{
 
289
#if !defined VMX86_VMX
 
290
   VMCI_ReleaseQueueMutex(qpair->produceQ);
 
291
#endif
 
292
}
 
293
 
 
294
 
 
295
/*
 
296
 *-----------------------------------------------------------------------------
 
297
 *
 
298
 * VMCIQPair_GetProduceIndexes --
 
299
 *
 
300
 *      This is the client interface for getting the current indexes of the
 
301
 *      QPair from the point of the view of the caller as the producer.
 
302
 *
 
303
 * Results:
 
304
 *      err, if < 0
 
305
 *      Success otherwise.
 
306
 *
 
307
 * Side effects:
 
308
 *      Windows blocking call.
 
309
 *
 
310
 *-----------------------------------------------------------------------------
 
311
 */
 
312
 
 
313
VMCI_EXPORT_SYMBOL(VMCIQPair_GetProduceIndexes)
 
314
int
 
315
VMCIQPair_GetProduceIndexes(const VMCIQPair *qpair, // IN
 
316
                            uint64 *producerTail,   // OUT
 
317
                            uint64 *consumerHead)   // OUT
 
318
{
 
319
   int result;
 
320
 
 
321
   if (!qpair) {
 
322
      return VMCI_ERROR_INVALID_ARGS;
 
323
   }
 
324
 
 
325
   VMCIQPairLock(qpair);
 
326
 
 
327
   if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
 
328
      result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
 
329
   } else {
 
330
      VMCIQueueHeader_GetPointers(qpair->produceQ->qHeader,
 
331
                                  qpair->consumeQ->qHeader,
 
332
                                  producerTail,
 
333
                                  consumerHead);
 
334
      result = VMCI_SUCCESS;
 
335
   }
 
336
 
 
337
   VMCIQPairUnlock(qpair);
 
338
 
 
339
   if (result == VMCI_SUCCESS &&
 
340
       ((producerTail && *producerTail >= qpair->produceQSize) ||
 
341
        (consumerHead && *consumerHead >= qpair->produceQSize))) {
 
342
      return VMCI_ERROR_INVALID_SIZE;
 
343
   }
 
344
 
 
345
   return result;
 
346
}
 
347
 
 
348
 
 
349
/*
 
350
 *-----------------------------------------------------------------------------
 
351
 *
 
352
 * VMCIQPair_GetConsumeIndexes --
 
353
 *
 
354
 *      This is the client interface for getting the current indexes of the
 
355
 *      QPair from the point of the view of the caller as the consumer.
 
356
 *
 
357
 * Results:
 
358
 *      err, if < 0
 
359
 *      Success otherwise.
 
360
 *
 
361
 * Side effects:
 
362
 *      Windows blocking call.
 
363
 *
 
364
 *-----------------------------------------------------------------------------
 
365
 */
 
366
 
 
367
VMCI_EXPORT_SYMBOL(VMCIQPair_GetConsumeIndexes)
 
368
int
 
369
VMCIQPair_GetConsumeIndexes(const VMCIQPair *qpair, // IN
 
370
                            uint64 *consumerTail,   // OUT
 
371
                            uint64 *producerHead)   // OUT
 
372
{
 
373
   int result;
 
374
 
 
375
   if (!qpair) {
 
376
      return VMCI_ERROR_INVALID_ARGS;
 
377
   }
 
378
 
 
379
   VMCIQPairLock(qpair);
 
380
 
 
381
   if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
 
382
      result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
 
383
   } else {
 
384
      VMCIQueueHeader_GetPointers(qpair->consumeQ->qHeader,
 
385
                                  qpair->produceQ->qHeader,
 
386
                                  consumerTail,
 
387
                                  producerHead);
 
388
      result = VMCI_SUCCESS;
 
389
   }
 
390
 
 
391
   VMCIQPairUnlock(qpair);
 
392
 
 
393
   if (result == VMCI_SUCCESS &&
 
394
       ((consumerTail && *consumerTail >= qpair->consumeQSize) ||
 
395
        (producerHead && *producerHead >= qpair->consumeQSize))) {
 
396
      return VMCI_ERROR_INVALID_SIZE;
 
397
   }
 
398
 
 
399
   return result;
 
400
}
 
401
 
 
402
 
 
403
/*
 
404
 *-----------------------------------------------------------------------------
 
405
 *
 
406
 * VMCIQPair_ProduceFreeSpace --
 
407
 *
 
408
 *      This is the client interface for getting the amount of free
 
409
 *      space in the QPair from the point of the view of the caller as
 
410
 *      the producer which is the common case.
 
411
 *
 
412
 * Results:
 
413
 *      Err, if < 0.
 
414
 *      Full queue if = 0.
 
415
 *      Number of available bytes into which data can be enqueued if > 0.
 
416
 *
 
417
 * Side effects:
 
418
 *      Windows blocking call.
 
419
 *
 
420
 *-----------------------------------------------------------------------------
 
421
 */
 
422
 
 
423
VMCI_EXPORT_SYMBOL(VMCIQPair_ProduceFreeSpace)
 
424
int64
 
425
VMCIQPair_ProduceFreeSpace(const VMCIQPair *qpair) // IN
 
426
{
 
427
   int64 result;
 
428
 
 
429
   if (!qpair) {
 
430
      return VMCI_ERROR_INVALID_ARGS;
 
431
   }
 
432
 
 
433
   VMCIQPairLock(qpair);
 
434
 
 
435
   if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
 
436
      result = 0;
 
437
   } else {
 
438
      result = VMCIQueueHeader_FreeSpace(qpair->produceQ->qHeader,
 
439
                                         qpair->consumeQ->qHeader,
 
440
                                         qpair->produceQSize);
 
441
   }
 
442
 
 
443
   VMCIQPairUnlock(qpair);
 
444
 
 
445
   return result;
 
446
}
 
447
 
 
448
 
 
449
/*
 
450
 *-----------------------------------------------------------------------------
 
451
 *
 
452
 * VMCIQPair_ConsumeFreeSpace --
 
453
 *
 
454
 *      This is the client interface for getting the amount of free
 
455
 *      space in the QPair from the point of the view of the caller as
 
456
 *      the consumer which is not the common case (see
 
457
 *      VMCIQPair_ProduceFreeSpace(), above).
 
458
 *
 
459
 * Results:
 
460
 *      Err, if < 0.
 
461
 *      Full queue if = 0.
 
462
 *      Number of available bytes into which data can be enqueued if > 0.
 
463
 *
 
464
 * Side effects:
 
465
 *      Windows blocking call.
 
466
 *
 
467
 *-----------------------------------------------------------------------------
 
468
 */
 
469
 
 
470
VMCI_EXPORT_SYMBOL(VMCIQPair_ConsumeFreeSpace)
 
471
int64
 
472
VMCIQPair_ConsumeFreeSpace(const VMCIQPair *qpair) // IN
 
473
{
 
474
   int64 result;
 
475
 
 
476
   if (!qpair) {
 
477
      return VMCI_ERROR_INVALID_ARGS;
 
478
   }
 
479
 
 
480
   VMCIQPairLock(qpair);
 
481
 
 
482
   if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
 
483
      result = 0;
 
484
   } else {
 
485
      result = VMCIQueueHeader_FreeSpace(qpair->consumeQ->qHeader,
 
486
                                         qpair->produceQ->qHeader,
 
487
                                         qpair->consumeQSize);
 
488
   }
 
489
 
 
490
   VMCIQPairUnlock(qpair);
 
491
 
 
492
   return result;
 
493
}
 
494
 
 
495
 
 
496
/*
 
497
 *-----------------------------------------------------------------------------
 
498
 *
 
499
 * VMCIQPair_ProduceBufReady --
 
500
 *
 
501
 *      This is the client interface for getting the amount of
 
502
 *      enqueued data in the QPair from the point of the view of the
 
503
 *      caller as the producer which is not the common case (see
 
504
 *      VMCIQPair_ConsumeBufReady(), above).
 
505
 *
 
506
 * Results:
 
507
 *      Err, if < 0.
 
508
 *      Empty queue if = 0.
 
509
 *      Number of bytes ready to be dequeued if > 0.
 
510
 *
 
511
 * Side effects:
 
512
 *      Windows blocking call.
 
513
 *
 
514
 *-----------------------------------------------------------------------------
 
515
 */
 
516
 
 
517
VMCI_EXPORT_SYMBOL(VMCIQPair_ProduceBufReady)
 
518
int64
 
519
VMCIQPair_ProduceBufReady(const VMCIQPair *qpair) // IN
 
520
{
 
521
   int64 result;
 
522
 
 
523
   if (!qpair) {
 
524
      return VMCI_ERROR_INVALID_ARGS;
 
525
   }
 
526
 
 
527
   VMCIQPairLock(qpair);
 
528
 
 
529
   if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
 
530
      result = 0;
 
531
   } else {
 
532
      result = VMCIQueueHeader_BufReady(qpair->produceQ->qHeader,
 
533
                                        qpair->consumeQ->qHeader,
 
534
                                        qpair->produceQSize);
 
535
   }
 
536
 
 
537
   VMCIQPairUnlock(qpair);
 
538
 
 
539
   return result;
 
540
}
 
541
 
 
542
 
 
543
/*
 
544
 *-----------------------------------------------------------------------------
 
545
 *
 
546
 * VMCIQPair_ConsumeBufReady --
 
547
 *
 
548
 *      This is the client interface for getting the amount of
 
549
 *      enqueued data in the QPair from the point of the view of the
 
550
 *      caller as the consumer which is the normal case.
 
551
 *
 
552
 * Results:
 
553
 *      Err, if < 0.
 
554
 *      Empty queue if = 0.
 
555
 *      Number of bytes ready to be dequeued if > 0.
 
556
 *
 
557
 * Side effects:
 
558
 *      Windows blocking call.
 
559
 *
 
560
 *-----------------------------------------------------------------------------
 
561
 */
 
562
 
 
563
VMCI_EXPORT_SYMBOL(VMCIQPair_ConsumeBufReady)
 
564
int64
 
565
VMCIQPair_ConsumeBufReady(const VMCIQPair *qpair) // IN
 
566
{
 
567
   int64 result;
 
568
 
 
569
   if (!qpair) {
 
570
      return VMCI_ERROR_INVALID_ARGS;
 
571
   }
 
572
 
 
573
   VMCIQPairLock(qpair);
 
574
 
 
575
   if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
 
576
      result = 0;
 
577
   } else {
 
578
      result = VMCIQueueHeader_BufReady(qpair->consumeQ->qHeader,
 
579
                                        qpair->produceQ->qHeader,
 
580
                                        qpair->consumeQSize);
 
581
   }
 
582
 
 
583
   VMCIQPairUnlock(qpair);
 
584
 
 
585
   return result;
 
586
}
 
587
 
 
588
 
 
589
/*
 
590
 *-----------------------------------------------------------------------------
 
591
 *
 
592
 * EnqueueLocked --
 
593
 *
 
594
 *      Enqueues a given buffer to the produce queue using the provided
 
595
 *      function. As many bytes as possible (space available in the queue)
 
596
 *      are enqueued.
 
597
 *
 
598
 *      Assumes the queue->mutex has been acquired.
 
599
 *
 
600
 * Results:
 
601
 *      VMCI_ERROR_QUEUEPAIR_NOSPACE if no space was available to enqueue data.
 
602
 *      VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
 
603
 *      (as defined by the queue size).
 
604
 *      VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer.
 
605
 *      VMCI_ERROR_QUEUEPAIR_NOTATTACHED, if the queue pair pages aren't
 
606
 *      available.
 
607
 *      Otherwise, the number of bytes written to the queue is returned.
 
608
 *
 
609
 * Side effects:
 
610
 *      Updates the tail pointer of the produce queue.
 
611
 *
 
612
 *-----------------------------------------------------------------------------
 
613
 */
 
614
 
 
615
static INLINE ssize_t
 
616
EnqueueLocked(VMCIQueue *produceQ,                   // IN
 
617
              const VMCIQueue *consumeQ,             // IN
 
618
              const uint64 produceQSize,             // IN
 
619
              const void *buf,                       // IN
 
620
              size_t bufSize,                        // IN
 
621
              int bufType,                           // IN
 
622
              VMCIMemcpyToQueueFunc memcpyToQueue)   // IN
 
623
{
 
624
   int64 freeSpace;
 
625
   uint64 tail;
 
626
   size_t written;
 
627
   ssize_t result;
 
628
 
 
629
#if !defined VMX86_VMX
 
630
   if (UNLIKELY(VMCI_EnqueueToDevNull(produceQ))) {
 
631
      return (ssize_t) bufSize;
 
632
   }
 
633
 
 
634
   if (UNLIKELY(!produceQ->qHeader || !consumeQ->qHeader)) {
 
635
      return VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
 
636
   }
 
637
#endif
 
638
 
 
639
   freeSpace = VMCIQueueHeader_FreeSpace(produceQ->qHeader,
 
640
                                         consumeQ->qHeader,
 
641
                                         produceQSize);
 
642
   if (freeSpace == 0) {
 
643
      return VMCI_ERROR_QUEUEPAIR_NOSPACE;
 
644
   }
 
645
 
 
646
   if (freeSpace < VMCI_SUCCESS) {
 
647
      return (ssize_t)freeSpace;
 
648
   }
 
649
 
 
650
   written = (size_t)(freeSpace > bufSize ? bufSize : freeSpace);
 
651
   tail = VMCIQueueHeader_ProducerTail(produceQ->qHeader);
 
652
   if (LIKELY(tail + written < produceQSize)) {
 
653
      result = memcpyToQueue(produceQ, tail, buf, 0, written, bufType);
 
654
   } else {
 
655
      /* Tail pointer wraps around. */
 
656
 
 
657
      const size_t tmp = (size_t)(produceQSize - tail);
 
658
 
 
659
      result = memcpyToQueue(produceQ, tail, buf, 0, tmp, bufType);
 
660
      if (result >= VMCI_SUCCESS) {
 
661
         result = memcpyToQueue(produceQ, 0, buf, tmp, written - tmp, bufType);
 
662
      }
 
663
   }
 
664
 
 
665
   if (result < VMCI_SUCCESS) {
 
666
      return result;
 
667
   }
 
668
 
 
669
   VMCIQueueHeader_AddProducerTail(produceQ->qHeader, written, produceQSize);
 
670
   return written;
 
671
}
 
672
 
 
673
 
 
674
/*
 
675
 *-----------------------------------------------------------------------------
 
676
 *
 
677
 * DequeueLocked --
 
678
 *
 
679
 *      Dequeues data (if available) from the given consume queue. Writes data
 
680
 *      to the user provided buffer using the provided function.
 
681
 *
 
682
 *      Assumes the queue->mutex has been acquired.
 
683
 *
 
684
 * Results:
 
685
 *      VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
 
686
 *      VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
 
687
 *      (as defined by the queue size).
 
688
 *      VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer.
 
689
 *      Otherwise the number of bytes dequeued is returned.
 
690
 *
 
691
 * Side effects:
 
692
 *      Updates the head pointer of the consume queue.
 
693
 *
 
694
 *-----------------------------------------------------------------------------
 
695
 */
 
696
 
 
697
static INLINE ssize_t
 
698
DequeueLocked(VMCIQueue *produceQ,                        // IN
 
699
              const VMCIQueue *consumeQ,                  // IN
 
700
              const uint64 consumeQSize,                  // IN
 
701
              void *buf,                                  // IN
 
702
              size_t bufSize,                             // IN
 
703
              int bufType,                                // IN
 
704
              VMCIMemcpyFromQueueFunc memcpyFromQueue,    // IN
 
705
              Bool updateConsumer)                        // IN
 
706
{
 
707
   int64 bufReady;
 
708
   uint64 head;
 
709
   size_t read;
 
710
   ssize_t result;
 
711
 
 
712
#if !defined VMX86_VMX
 
713
   if (UNLIKELY(!produceQ->qHeader ||
 
714
                !consumeQ->qHeader)) {
 
715
      return VMCI_ERROR_QUEUEPAIR_NODATA;
 
716
   }
 
717
#endif
 
718
 
 
719
   bufReady = VMCIQueueHeader_BufReady(consumeQ->qHeader,
 
720
                                       produceQ->qHeader,
 
721
                                       consumeQSize);
 
722
   if (bufReady == 0) {
 
723
      return VMCI_ERROR_QUEUEPAIR_NODATA;
 
724
   }
 
725
   if (bufReady < VMCI_SUCCESS) {
 
726
      return (ssize_t)bufReady;
 
727
   }
 
728
 
 
729
   read = (size_t)(bufReady > bufSize ? bufSize : bufReady);
 
730
   head = VMCIQueueHeader_ConsumerHead(produceQ->qHeader);
 
731
   if (LIKELY(head + read < consumeQSize)) {
 
732
      result = memcpyFromQueue(buf, 0, consumeQ, head, read, bufType);
 
733
   } else {
 
734
      /* Head pointer wraps around. */
 
735
 
 
736
      const size_t tmp = (size_t)(consumeQSize - head);
 
737
 
 
738
      result = memcpyFromQueue(buf, 0, consumeQ, head, tmp, bufType);
 
739
      if (result >= VMCI_SUCCESS) {
 
740
         result = memcpyFromQueue(buf, tmp, consumeQ, 0, read - tmp, bufType);
 
741
      }
 
742
   }
 
743
 
 
744
   if (result < VMCI_SUCCESS) {
 
745
      return result;
 
746
   }
 
747
 
 
748
   if (updateConsumer) {
 
749
      VMCIQueueHeader_AddConsumerHead(produceQ->qHeader,
 
750
                                      read,
 
751
                                      consumeQSize);
 
752
   }
 
753
 
 
754
   return read;
 
755
}
 
756
 
 
757
 
 
758
/*
 
759
 *-----------------------------------------------------------------------------
 
760
 *
 
761
 * VMCIQPair_Enqueue --
 
762
 *
 
763
 *      This is the client interface for enqueueing data into the queue.
 
764
 *
 
765
 * Results:
 
766
 *      Err, if < 0.
 
767
 *      Number of bytes enqueued if >= 0.
 
768
 *
 
769
 * Side effects:
 
770
 *      Windows blocking call.
 
771
 *
 
772
 *-----------------------------------------------------------------------------
 
773
 */
 
774
 
 
775
VMCI_EXPORT_SYMBOL(VMCIQPair_Enqueue)
 
776
ssize_t
 
777
VMCIQPair_Enqueue(VMCIQPair *qpair,        // IN
 
778
                  const void *buf,         // IN
 
779
                  size_t bufSize,          // IN
 
780
                  int bufType)             // IN
 
781
{
 
782
   ssize_t result;
 
783
 
 
784
   if (!qpair || !buf) {
 
785
      return VMCI_ERROR_INVALID_ARGS;
 
786
   }
 
787
 
 
788
   VMCIQPairLock(qpair);
 
789
 
 
790
   result = EnqueueLocked(qpair->produceQ,
 
791
                          qpair->consumeQ,
 
792
                          qpair->produceQSize,
 
793
                          buf, bufSize, bufType,
 
794
                          VMCIMemcpyToQueue);
 
795
 
 
796
   VMCIQPairUnlock(qpair);
 
797
 
 
798
   return result;
 
799
}
 
800
 
 
801
 
 
802
/*
 
803
 *-----------------------------------------------------------------------------
 
804
 *
 
805
 * VMCIQPair_Dequeue --
 
806
 *
 
807
 *      This is the client interface for dequeueing data from the queue.
 
808
 *
 
809
 * Results:
 
810
 *      Err, if < 0.
 
811
 *      Number of bytes dequeued if >= 0.
 
812
 *
 
813
 * Side effects:
 
814
 *      Windows blocking call.
 
815
 *
 
816
 *-----------------------------------------------------------------------------
 
817
 */
 
818
 
 
819
VMCI_EXPORT_SYMBOL(VMCIQPair_Dequeue)
 
820
ssize_t
 
821
VMCIQPair_Dequeue(VMCIQPair *qpair,        // IN
 
822
                  void *buf,               // IN
 
823
                  size_t bufSize,          // IN
 
824
                  int bufType)             // IN
 
825
{
 
826
   ssize_t result;
 
827
 
 
828
   if (!qpair || !buf) {
 
829
      return VMCI_ERROR_INVALID_ARGS;
 
830
   }
 
831
 
 
832
   VMCIQPairLock(qpair);
 
833
 
 
834
   result = DequeueLocked(qpair->produceQ,
 
835
                          qpair->consumeQ,
 
836
                          qpair->consumeQSize,
 
837
                          buf, bufSize, bufType,
 
838
                          VMCIMemcpyFromQueue,
 
839
                          TRUE);
 
840
 
 
841
   VMCIQPairUnlock(qpair);
 
842
 
 
843
   return result;
 
844
}
 
845
 
 
846
 
 
847
/*
 
848
 *-----------------------------------------------------------------------------
 
849
 *
 
850
 * VMCIQPair_Peek --
 
851
 *
 
852
 *      This is the client interface for peeking into a queue.  (I.e.,
 
853
 *      copy data from the queue without updating the head pointer.)
 
854
 *
 
855
 * Results:
 
856
 *      Err, if < 0.
 
857
 *      Number of bytes peeked, if >= 0.
 
858
 *
 
859
 * Side effects:
 
860
 *      Windows blocking call.
 
861
 *
 
862
 *-----------------------------------------------------------------------------
 
863
 */
 
864
 
 
865
VMCI_EXPORT_SYMBOL(VMCIQPair_Peek)
 
866
ssize_t
 
867
VMCIQPair_Peek(VMCIQPair *qpair,    // IN
 
868
               void *buf,           // IN
 
869
               size_t bufSize,      // IN
 
870
               int bufType)         // IN
 
871
{
 
872
   ssize_t result;
 
873
 
 
874
   if (!qpair || !buf) {
 
875
      return VMCI_ERROR_INVALID_ARGS;
 
876
   }
 
877
 
 
878
   VMCIQPairLock(qpair);
 
879
 
 
880
   result = DequeueLocked(qpair->produceQ,
 
881
                          qpair->consumeQ,
 
882
                          qpair->consumeQSize,
 
883
                          buf, bufSize, bufType,
 
884
                          VMCIMemcpyFromQueue,
 
885
                          FALSE);
 
886
 
 
887
   VMCIQPairUnlock(qpair);
 
888
 
 
889
   return result;
 
890
}
 
891
 
 
892
 
 
893
#if defined (SOLARIS) || (defined(__APPLE__) && !defined (VMX86_TOOLS)) || \
 
894
    (defined(__linux__) && defined(__KERNEL__)) || \
 
895
    (defined(_WIN32) && defined(WINNT_DDK))
 
896
 
 
897
/*
 
898
 *-----------------------------------------------------------------------------
 
899
 *
 
900
 * VMCIQPair_EnqueueV --
 
901
 *
 
902
 *      This is the client interface for enqueueing data into the queue.
 
903
 *
 
904
 * Results:
 
905
 *      Err, if < 0.
 
906
 *      Number of bytes enqueued if >= 0.
 
907
 *
 
908
 * Side effects:
 
909
 *      Windows blocking call.
 
910
 *
 
911
 *-----------------------------------------------------------------------------
 
912
 */
 
913
 
 
914
VMCI_EXPORT_SYMBOL(VMCIQPair_EnqueueV)
 
915
ssize_t
 
916
VMCIQPair_EnqueueV(VMCIQPair *qpair,        // IN
 
917
                   void *iov,               // IN
 
918
                   size_t iovSize,          // IN
 
919
                   int bufType)             // IN
 
920
{
 
921
   ssize_t result;
 
922
 
 
923
   if (!qpair || !iov) {
 
924
      return VMCI_ERROR_INVALID_ARGS;
 
925
   }
 
926
 
 
927
   VMCIQPairLock(qpair);
 
928
 
 
929
   result = EnqueueLocked(qpair->produceQ,
 
930
                          qpair->consumeQ,
 
931
                          qpair->produceQSize,
 
932
                          iov, iovSize, bufType,
 
933
                          VMCIMemcpyToQueueV);
 
934
 
 
935
   VMCIQPairUnlock(qpair);
 
936
 
 
937
   return result;
 
938
}
 
939
 
 
940
 
 
941
/*
 
942
 *-----------------------------------------------------------------------------
 
943
 *
 
944
 * VMCIQPair_DequeueV --
 
945
 *
 
946
 *      This is the client interface for dequeueing data from the queue.
 
947
 *
 
948
 * Results:
 
949
 *      Err, if < 0.
 
950
 *      Number of bytes dequeued if >= 0.
 
951
 *
 
952
 * Side effects:
 
953
 *      Windows blocking call.
 
954
 *
 
955
 *-----------------------------------------------------------------------------
 
956
 */
 
957
 
 
958
VMCI_EXPORT_SYMBOL(VMCIQPair_DequeueV)
 
959
ssize_t
 
960
VMCIQPair_DequeueV(VMCIQPair *qpair,         // IN
 
961
                   void *iov,                // IN
 
962
                   size_t iovSize,           // IN
 
963
                   int bufType)              // IN
 
964
{
 
965
   ssize_t result;
 
966
 
 
967
   VMCIQPairLock(qpair);
 
968
 
 
969
   if (!qpair || !iov) {
 
970
      return VMCI_ERROR_INVALID_ARGS;
 
971
   }
 
972
 
 
973
   result = DequeueLocked(qpair->produceQ,
 
974
                          qpair->consumeQ,
 
975
                          qpair->consumeQSize,
 
976
                          iov, iovSize, bufType,
 
977
                          VMCIMemcpyFromQueueV,
 
978
                          TRUE);
 
979
 
 
980
   VMCIQPairUnlock(qpair);
 
981
 
 
982
   return result;
 
983
}
 
984
 
 
985
 
 
986
/*
 
987
 *-----------------------------------------------------------------------------
 
988
 *
 
989
 * VMCIQPair_PeekV --
 
990
 *
 
991
 *      This is the client interface for peeking into a queue.  (I.e.,
 
992
 *      copy data from the queue without updating the head pointer.)
 
993
 *
 
994
 * Results:
 
995
 *      Err, if < 0.
 
996
 *      Number of bytes peeked, if >= 0.
 
997
 *
 
998
 * Side effects:
 
999
 *      Windows blocking call.
 
1000
 *
 
1001
 *-----------------------------------------------------------------------------
 
1002
 */
 
1003
 
 
1004
VMCI_EXPORT_SYMBOL(VMCIQPair_PeekV)
 
1005
ssize_t
 
1006
VMCIQPair_PeekV(VMCIQPair *qpair,           // IN
 
1007
                void *iov,                  // IN
 
1008
                size_t iovSize,             // IN
 
1009
                int bufType)                // IN
 
1010
{
 
1011
   ssize_t result;
 
1012
 
 
1013
   if (!qpair || !iov) {
 
1014
      return VMCI_ERROR_INVALID_ARGS;
 
1015
   }
 
1016
 
 
1017
   VMCIQPairLock(qpair);
 
1018
 
 
1019
   result = DequeueLocked(qpair->produceQ,
 
1020
                          qpair->consumeQ,
 
1021
                          qpair->consumeQSize,
 
1022
                          iov, iovSize, bufType,
 
1023
                          VMCIMemcpyFromQueueV,
 
1024
                          FALSE);
 
1025
 
 
1026
   VMCIQPairUnlock(qpair);
 
1027
 
 
1028
   return result;
 
1029
}
 
1030
 
 
1031
#endif /* Systems that support struct iovec */