~n-muench/ubuntu/precise/open-vm-tools/open-vm-tools.raring-precise.backport

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Nate Muench
  • Date: 2012-01-23 16:09:45 UTC
  • mfrom: (1.4.6) (2.4.26 sid)
  • Revision ID: package-import@ubuntu.com-20120123160945-b6s0r1vkcovucpf3
Tags: 2011.12.20-562307-0ubuntu1
* Merge latest upstream git tag. Fixes building on Precise
  (LP: #898289, LP: #905612)

* Items merged from Debian unstable:
  - debian/control:
    + open-vm-tools recommends open-vm-dkms. (LP: #598933)
    + open-vm-tools now suggests open-vm-toolbox. (LP: #604998)
  (From 2011.08.21-471295-1 release)
  - Updating maintainer and uploaders fields.
  - Removing vcs fields.
  - Removing references to Daniel's old email address.
  - Updating years in copyright file.
  - Updating to standards version 3.9.2.
  - Updating to debhelper version 8.
  - Switching to source format 3.0 (quilt).
  - Removing manual chrpath setting.
  - Removing exclusion from plugins from debhelper shlibs.
  - Rediffing kvers.patch.
  (From 2011.09.23-491607-1 release)
  - Marking binary architecture-dependend packages as linux and kfreebsd
  only.
  - Removing liburiparser-dev from build-depends as upstream dropped
  unity support.
  - Building with libproc-dev on amd64 again.
  - Dropping disabling of dnet support.
  (From 2011.09.23-491607-2 release)
  - Adding doxygen to build-depends for api documentation.
  - Adding libcunit1-dev to build-depends for test suites.
  - Minimizing rules file.
  - Adding open-vm-tools-dev package, containing only the api
    documentation for now.
  (From 2011.09.23-491607-3 release)
  - Sorting overrides in rules alphabetically.
  - Compacting copyright file.
  - Adding udev rule to set timeout for vmware scsi devices
  (From 2011.12.20-562307-1 release)
  - Adding patch to correct typo in upstreams dkms configuration

* Remaining Changes:
  - Remove Stable part of version numbering.
  - debian folder:
    + Re-added open-vm-dkms.postinst & open-vm-dkms.prerm.
      * Allows dkms modules to compile upon installation.
  - debian/control:
    + Re-add open-vm-source and make into a transitional package
      for open-vm-toolbox.
    + Return dependancies that were moved to open-vm-tools back to
      open-vm-toolbox.
  - debian/rules and debian/open-vm-toolbox.lintian-overrides:
    + Make vmware-user-suid-wrapper suid-root
  - debian/rules:
    + Added CFLAGS field with -Wno-deprecated-declarations
      * Will suppress issues with glib 2.31 or later.
    + Add line to copy vmware-xdg-detect-de into place.
    + Install vmware-user.desktop through toolbox package.
  - debian/open-vm-tools.init:
    + Re-add 'modprobe [-r] vmblock'.
    + Add 'modprobe [-r] vmxnet'.
      * Incase it's not loaded during boot.
    + Remove and re-add pcnet32 module
      * Will be done before (remove) and after (readd) vmxnet module
        is added.
      * If vmxnet doesn't exist (aka modules fail to build), pcnet32 can be
        still used for network connectivity.
      * Workaround until a better fix can be done.
  - Re-add gnome-session to debian/local/xautostart.conf
  - Manpages removed (from debian/manpages):
    + vmmemctl.9
    + vmxnet3.9
    + Remove references to manpages that have been removed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*********************************************************
2
 
 * Copyright (C) 2007 VMware, Inc. All rights reserved.
 
2
 * Copyright (C) 2007-2011 VMware, Inc. All rights reserved.
3
3
 *
4
4
 * This program is free software; you can redistribute it and/or modify it
5
5
 * under the terms of the GNU General Public License as published by the
40
40
#if defined(VMKERNEL)
41
41
#  include "vmciVmkInt.h"
42
42
#  include "vm_libc.h"
43
 
#  include "helper_ext.h"
44
43
#endif
45
44
 
46
45
#define LGPFX "VMCIQueuePair: "
47
46
 
48
 
/*
49
 
 * The context that creates the QueuePair becomes producer of produce queue,
50
 
 * and consumer of consume queue. The context on other end for the QueuePair
51
 
 * has roles reversed for these two queues.
 
47
 
 
48
/*
 
49
 * In the following, we will distinguish between two kinds of VMX processes -
 
50
 * the ones with versions lower than VMCI_VERSION_NOVMVM that use specialized
 
51
 * VMCI page files in the VMX and supporting VM to VM communication) and the
 
52
 * newer ones that use the guest memory directly. We will in the following refer
 
53
 * to the older VMX versions as old-style VMX'en, and the newer ones as new-style
 
54
 * VMX'en.
 
55
 *
 
56
 * The state transition datagram is as follows (the VMCIQPB_ prefix has been
 
57
 * removed for readability) - see below for more details on the transtions:
 
58
 *
 
59
 *            --------------  NEW  -------------
 
60
 *            |                                |
 
61
 *           \_/                              \_/
 
62
 *     CREATED_NO_MEM <-----------------> CREATED_MEM
 
63
 *            |    |                           |
 
64
 *            |    o-----------------------o   |
 
65
 *            |                            |   |
 
66
 *           \_/                          \_/ \_/
 
67
 *     ATTACHED_NO_MEM <----------------> ATTACHED_MEM
 
68
 *            |                            |   |
 
69
 *            |     o----------------------o   |
 
70
 *            |     |                          |
 
71
 *           \_/   \_/                        \_/
 
72
 *     SHUTDOWN_NO_MEM <----------------> SHUTDOWN_MEM
 
73
 *            |                                |
 
74
 *            |                                |
 
75
 *            -------------> gone <-------------
 
76
 *
 
77
 * In more detail. When a VMCI queue pair is first created, it will be in the
 
78
 * VMCIQPB_NEW state. It will then move into one of the following states:
 
79
 * - VMCIQPB_CREATED_NO_MEM: this state indicates that either:
 
80
 *     - the created was performed by a host endpoint, in which case there is no
 
81
 *       backing memory yet.
 
82
 *     - the create was initiated by an old-style VMX, that uses
 
83
 *       VMCIQPBroker_SetPageStore to specify the UVAs of the queue pair at a
 
84
 *       later point in time. This state can be distinguished from the one above
 
85
 *       by the context ID of the creator. A host side is not allowed to attach
 
86
 *       until the page store has been set.
 
87
 * - VMCIQPB_CREATED_MEM: this state is the result when the queue pair is created
 
88
 *     by a VMX using the queue pair device backend that sets the UVAs of the
 
89
 *     queue pair immediately and stores the information for later attachers. At
 
90
 *     this point, it is ready for the host side to attach to it.
 
91
 * Once the queue pair is in one of the created states (with the exception of the
 
92
 * case mentioned for older VMX'en above), it is possible to attach to the queue
 
93
 * pair. Again we have two new states possible:
 
94
 * - VMCIQPB_ATTACHED_MEM: this state can be reached through the following paths:
 
95
 *     - from VMCIQPB_CREATED_NO_MEM when a new-style VMX allocates a queue pair,
 
96
 *       and attaches to a queue pair previously created by the host side.
 
97
 *     - from VMCIQPB_CREATED_MEM when the host side attaches to a queue pair
 
98
 *       already created by a guest.
 
99
 *     - from VMCIQPB_ATTACHED_NO_MEM, when an old-style VMX calls
 
100
 *       VMCIQPBroker_SetPageStore (see below).
 
101
 * - VMCIQPB_ATTACHED_NO_MEM: If the queue pair already was in the
 
102
 *     VMCIQPB_CREATED_NO_MEM due to a host side create, an old-style VMX will
 
103
 *     bring the queue pair into this state. Once VMCIQPBroker_SetPageStore is
 
104
 *     called to register the user memory, the VMCIQPB_ATTACH_MEM state will be
 
105
 *     entered.
 
106
 * From the attached queue pair, the queue pair can enter the shutdown states
 
107
 * when either side of the queue pair detaches. If the guest side detaches first,
 
108
 * the queue pair will enter the VMCIQPB_SHUTDOWN_NO_MEM state, where the content
 
109
 * of the queue pair will no longer be available. If the host side detaches first,
 
110
 * the queue pair will either enter the VMCIQPB_SHUTDOWN_MEM, if the guest memory
 
111
 * is currently mapped, or VMCIQPB_SHUTDOWN_NO_MEM, if the guest memory is not
 
112
 * mapped (e.g., the host detaches while a guest is stunned).
 
113
 *
 
114
 * New-style VMX'en will also unmap guest memory, if the guest is quiesced, e.g.,
 
115
 * during a snapshot operation. In that case, the guest memory will no longer be
 
116
 * available, and the queue pair will transition from *_MEM state to a *_NO_MEM
 
117
 * state. The VMX may later map the memory once more, in which case the queue
 
118
 * pair will transition from the *_NO_MEM state at that point back to the *_MEM
 
119
 * state. Note that the *_NO_MEM state may have changed, since the peer may have
 
120
 * either attached or detached in the meantime. The values are laid out such that
 
121
 * ++ on a state will move from a *_NO_MEM to a *_MEM state, and vice versa.
 
122
 */
 
123
 
 
124
typedef enum {
 
125
   VMCIQPB_NEW,
 
126
   VMCIQPB_CREATED_NO_MEM,
 
127
   VMCIQPB_CREATED_MEM,
 
128
   VMCIQPB_ATTACHED_NO_MEM,
 
129
   VMCIQPB_ATTACHED_MEM,
 
130
   VMCIQPB_SHUTDOWN_NO_MEM,
 
131
   VMCIQPB_SHUTDOWN_MEM,
 
132
   VMCIQPB_GONE
 
133
} QPBrokerState;
 
134
 
 
135
#define QPBROKERSTATE_HAS_MEM(_qpb) (_qpb->state == VMCIQPB_CREATED_MEM || \
 
136
                                     _qpb->state == VMCIQPB_ATTACHED_MEM || \
 
137
                                     _qpb->state == VMCIQPB_SHUTDOWN_MEM)
 
138
 
 
139
/*
 
140
 * In the queue pair broker, we always use the guest point of view for
 
141
 * the produce and consume queue values and references, e.g., the
 
142
 * produce queue size stored is the guests produce queue size. The
 
143
 * host endpoint will need to swap these around. The only exception is
 
144
 * the local queue pairs on the host, in which case the host endpoint
 
145
 * that creates the queue pair will have the right orientation, and
 
146
 * the attaching host endpoint will need to swap.
52
147
 */
53
148
 
54
149
typedef struct QueuePairEntry {
65
160
   QueuePairEntry       qp;
66
161
   VMCIId               createId;
67
162
   VMCIId               attachId;
68
 
   Bool                 pageStoreSet;
69
 
   Bool                 allowAttach;
 
163
   QPBrokerState        state;
70
164
   Bool                 requireTrustedAttach;
71
165
   Bool                 createdByTrusted;
72
 
#ifdef VMKERNEL
73
 
   QueuePairPageStore   store;
74
 
#elif defined(__linux__) || defined(_WIN32) || defined(__APPLE__) || \
75
 
      defined(SOLARIS)
76
 
   /*
77
 
    * Always created but only used if a host endpoint attaches to this
78
 
    * queue.
79
 
    */
80
 
 
 
166
   Bool                 vmciPageFiles;  // Created by VMX using VMCI page files
81
167
   VMCIQueue           *produceQ;
82
168
   VMCIQueue           *consumeQ;
83
 
   char                 producePageFile[VMCI_PATH_MAX];
84
 
   char                 consumePageFile[VMCI_PATH_MAX];
85
 
   PageStoreAttachInfo *attachInfo;
86
 
#endif
 
169
   VMCIQueueHeader      savedProduceQ;
 
170
   VMCIQueueHeader      savedConsumeQ;
 
171
   VMCIEventReleaseCB   wakeupCB;
 
172
   void                *clientData;
 
173
   void                *localMem; // Kernel memory for local queue pair
87
174
} QPBrokerEntry;
88
175
 
89
176
#if !defined(VMKERNEL)
97
184
} QPGuestEndpoint;
98
185
#endif
99
186
 
100
 
#ifdef VMKERNEL
101
 
typedef VMCILock VMCIQPLock;
102
 
# define VMCIQPLock_Init(_l, _r) \
103
 
   _r = VMCI_InitLock(_l, "VMCIQPLock", VMCI_LOCK_RANK_HIGH)
104
 
# define VMCIQPLock_Destroy(_l)  VMCI_CleanupLock(_l)
105
 
# define VMCIQPLock_Acquire(_l)  VMCI_GrabLock(_l, NULL)
106
 
# define VMCIQPLock_Release(_l)  VMCI_ReleaseLock(_l, 0)
107
 
#else
108
 
typedef VMCIMutex VMCIQPLock;
109
 
# define VMCIQPLock_Init(_l, _r) _r = VMCIMutex_Init(_l)
110
 
# define VMCIQPLock_Destroy(_l)  VMCIMutex_Destroy(_l)
111
 
# define VMCIQPLock_Acquire(_l)  VMCIMutex_Acquire(_l)
112
 
# define VMCIQPLock_Release(_l)  VMCIMutex_Release(_l)
113
 
#endif
114
 
 
115
187
typedef struct QueuePairList {
116
188
   VMCIList       head;
117
189
   Atomic_uint32  hibernate;
118
 
   VMCIQPLock     lock;
 
190
   VMCIMutex      mutex;
119
191
} QueuePairList;
120
192
 
121
193
static QueuePairList qpBrokerList;
122
194
 
 
195
#define QPE_NUM_PAGES(_QPE) ((uint32)(CEILING(_QPE.produceSize, PAGE_SIZE) + \
 
196
                                      CEILING(_QPE.consumeSize, PAGE_SIZE) + 2))
 
197
 
123
198
#if !defined(VMKERNEL)
124
199
  static QueuePairList qpGuestEndpoints;
125
200
  static VMCIHandleArray *hibernateFailedList;
126
201
  static VMCILock hibernateFailedListLock;
127
202
#endif
128
203
 
 
204
static void VMCIQPBrokerLock(void);
 
205
static  void VMCIQPBrokerUnlock(void);
 
206
 
129
207
static QueuePairEntry *QueuePairList_FindEntry(QueuePairList *qpList,
130
208
                                               VMCIHandle handle);
131
209
static void QueuePairList_AddEntry(QueuePairList *qpList,
136
214
 
137
215
static int QueuePairNotifyPeer(Bool attach, VMCIHandle handle, VMCIId myId,
138
216
                               VMCIId peerId);
 
217
 
139
218
static int VMCIQPBrokerAllocInt(VMCIHandle handle, VMCIId peer,
140
219
                                uint32 flags, VMCIPrivilegeFlags privFlags,
141
220
                                uint64 produceSize,
142
221
                                uint64 consumeSize,
143
222
                                QueuePairPageStore *pageStore,
144
223
                                VMCIContext *context,
145
 
                                QPBrokerEntry **ent);
146
 
 
147
 
#if !defined(VMKERNEL)
 
224
                                VMCIEventReleaseCB wakeupCB,
 
225
                                void *clientData,
 
226
                                QPBrokerEntry **ent,
 
227
                                Bool *swap);
 
228
static int VMCIQPBrokerAttach(QPBrokerEntry *entry,
 
229
                              VMCIId peer,
 
230
                              uint32 flags,
 
231
                              VMCIPrivilegeFlags privFlags,
 
232
                              uint64 produceSize,
 
233
                              uint64 consumeSize,
 
234
                              QueuePairPageStore *pageStore,
 
235
                              VMCIContext *context,
 
236
                              VMCIEventReleaseCB wakeupCB,
 
237
                              void *clientData,
 
238
                              QPBrokerEntry **ent);
 
239
static int VMCIQPBrokerCreate(VMCIHandle handle,
 
240
                              VMCIId peer,
 
241
                              uint32 flags,
 
242
                              VMCIPrivilegeFlags privFlags,
 
243
                              uint64 produceSize,
 
244
                              uint64 consumeSize,
 
245
                              QueuePairPageStore *pageStore,
 
246
                              VMCIContext *context,
 
247
                              VMCIEventReleaseCB wakeupCB,
 
248
                              void *clientData,
 
249
                              QPBrokerEntry **ent);
148
250
static int VMCIQueuePairAllocHostWork(VMCIHandle *handle, VMCIQueue **produceQ,
149
251
                                      uint64 produceSize, VMCIQueue **consumeQ,
150
252
                                      uint64 consumeSize,
151
253
                                      VMCIId peer, uint32 flags,
152
 
                                      VMCIPrivilegeFlags privFlags);
 
254
                                      VMCIPrivilegeFlags privFlags,
 
255
                                      VMCIEventReleaseCB wakeupCB,
 
256
                                      void *clientData);
153
257
static int VMCIQueuePairDetachHostWork(VMCIHandle handle);
154
258
 
 
259
static int QueuePairSaveHeaders(QPBrokerEntry *entry);
 
260
static void QueuePairResetSavedHeaders(QPBrokerEntry *entry);
 
261
 
 
262
#if !defined(VMKERNEL)
 
263
 
155
264
static int QueuePairNotifyPeerLocal(Bool attach, VMCIHandle handle);
156
265
 
157
266
static QPGuestEndpoint *QPGuestEndpointCreate(VMCIHandle handle,
173
282
 
174
283
extern int VMCI_SendDatagram(VMCIDatagram *);
175
284
 
 
285
#endif
 
286
 
176
287
 
177
288
/*
178
289
 *-----------------------------------------------------------------------------
201
312
                    VMCIId     peer,              // IN
202
313
                    uint32     flags,             // IN
203
314
                    VMCIPrivilegeFlags privFlags, // IN
204
 
                    Bool       guestEndpoint)     // IN
 
315
                    Bool       guestEndpoint,     // IN
 
316
                    VMCIEventReleaseCB wakeupCB,  // IN
 
317
                    void *clientData)             // IN
205
318
{
206
319
   if (!handle || !produceQ || !consumeQ || (!produceSize && !consumeSize) ||
207
320
       (flags & ~VMCI_QP_ALL_FLAGS)) {
209
322
   }
210
323
 
211
324
   if (guestEndpoint) {
 
325
#if !defined(VMKERNEL)
212
326
      return VMCIQueuePairAllocGuestWork(handle, produceQ, produceSize, consumeQ,
213
327
                                         consumeSize, peer, flags, privFlags);
 
328
#else
 
329
      return VMCI_ERROR_INVALID_ARGS;
 
330
#endif
214
331
   } else {
215
332
      return VMCIQueuePairAllocHostWork(handle, produceQ, produceSize, consumeQ,
216
 
                                        consumeSize, peer, flags, privFlags);
 
333
                                        consumeSize, peer, flags, privFlags,
 
334
                                        wakeupCB, clientData);
217
335
   }
218
336
}
219
337
 
244
362
   }
245
363
 
246
364
   if (guestEndpoint) {
 
365
#if !defined(VMKERNEL)
247
366
      return VMCIQueuePairDetachGuestWork(handle);
 
367
#else
 
368
      return VMCI_ERROR_INVALID_ARGS;
 
369
#endif
248
370
   } else {
249
371
      return VMCIQueuePairDetachHostWork(handle);
250
372
   }
251
373
}
252
 
#endif // !defined(VMKERNEL)
253
374
 
254
375
 
255
376
/*
275
396
 
276
397
   VMCIList_Init(&qpList->head);
277
398
   Atomic_Write(&qpList->hibernate, 0);
278
 
   VMCIQPLock_Init(&qpList->lock, ret);
279
 
 
 
399
   ret = VMCIMutex_Init(&qpList->mutex, "VMCIQPListLock",
 
400
                        VMCI_SEMA_RANK_QUEUEPAIRLIST);
280
401
   return ret;
281
402
}
282
403
 
286
407
 *
287
408
 * QueuePairList_Destroy --
288
409
 *
289
 
 *      Destroy the list's lock.
 
410
 *      Destroy the list's mutex.
290
411
 *
291
412
 * Results:
292
413
 *      None.
300
421
static INLINE void
301
422
QueuePairList_Destroy(QueuePairList *qpList)
302
423
{
303
 
   VMCIQPLock_Destroy(&qpList->lock);
 
424
   VMCIMutex_Destroy(&qpList->mutex);
304
425
   VMCIList_Init(&qpList->head);
305
426
}
306
427
 
308
429
/*
309
430
 *-----------------------------------------------------------------------------
310
431
 *
311
 
 * VMCIQPBroker_Lock --
 
432
 * VMCIQPBrokerLock --
312
433
 *
313
 
 *      Acquires the lock protecting a VMCI queue pair broker transaction.
 
434
 *      Acquires the mutex protecting a VMCI queue pair broker transaction.
314
435
 *
315
436
 * Results:
316
437
 *      None.
321
442
 *-----------------------------------------------------------------------------
322
443
 */
323
444
 
324
 
void
325
 
VMCIQPBroker_Lock(void)
 
445
static void
 
446
VMCIQPBrokerLock(void)
326
447
{
327
 
   VMCIQPLock_Acquire(&qpBrokerList.lock);
 
448
   VMCIMutex_Acquire(&qpBrokerList.mutex);
328
449
}
329
450
 
330
451
 
331
452
/*
332
453
 *-----------------------------------------------------------------------------
333
454
 *
334
 
 * VMCIQPBroker_Unlock --
 
455
 * VMCIQPBrokerUnlock --
335
456
 *
336
 
 *      Releases the lock protecting a VMCI queue pair broker transaction.
 
457
 *      Releases the mutex protecting a VMCI queue pair broker transaction.
337
458
 *
338
459
 * Results:
339
460
 *      None.
344
465
 *-----------------------------------------------------------------------------
345
466
 */
346
467
 
347
 
void
348
 
VMCIQPBroker_Unlock(void)
 
468
static void
 
469
VMCIQPBrokerUnlock(void)
349
470
{
350
 
   VMCIQPLock_Release(&qpBrokerList.lock);
 
471
   VMCIMutex_Release(&qpBrokerList.mutex);
351
472
}
352
473
 
353
474
 
476
597
/*
477
598
 *-----------------------------------------------------------------------------
478
599
 *
479
 
 * QueuePairDenyConnection --
480
 
 *
481
 
 *      On ESX we check if the domain names of the two contexts match.
482
 
 *      Otherwise we deny the connection.  We always allow the connection on
483
 
 *      hosted.
484
 
 *
485
 
 * Results:
486
 
 *      Boolean result.
487
 
 *
488
 
 * Side effects:
489
 
 *      None.
490
 
 *
491
 
 *-----------------------------------------------------------------------------
492
 
 */
493
 
 
494
 
static INLINE Bool
495
 
QueuePairDenyConnection(VMCIId contextId, // IN:  Unused on hosted
496
 
                        VMCIId peerId)    // IN:  Unused on hosted
497
 
{
498
 
#ifndef VMKERNEL
499
 
   return FALSE; /* Allow on hosted. */
500
 
#else
501
 
   char contextDomain[VMCI_DOMAIN_NAME_MAXLEN];
502
 
   char peerDomain[VMCI_DOMAIN_NAME_MAXLEN];
503
 
 
504
 
   ASSERT(contextId != VMCI_INVALID_ID);
505
 
   if (peerId == VMCI_INVALID_ID) {
506
 
      return FALSE; /* Allow. */
507
 
   }
508
 
   if (VMCIContext_GetDomainName(contextId, contextDomain,
509
 
                                 sizeof contextDomain) != VMCI_SUCCESS) {
510
 
      return TRUE; /* Deny. */
511
 
   }
512
 
   if (VMCIContext_GetDomainName(peerId, peerDomain, sizeof peerDomain) !=
513
 
       VMCI_SUCCESS) {
514
 
      return TRUE; /* Deny. */
515
 
   }
516
 
   return strcmp(contextDomain, peerDomain) ? TRUE : /* Deny. */
517
 
                                              FALSE; /* Allow. */
518
 
#endif
519
 
}
520
 
 
521
 
 
522
 
/*
523
 
 *-----------------------------------------------------------------------------
524
 
 *
525
600
 * VMCIQPBroker_Init --
526
601
 *
527
602
 *      Initalizes queue pair broker state.
563
638
{
564
639
   QPBrokerEntry *entry;
565
640
 
566
 
   VMCIQPBroker_Lock();
 
641
   VMCIQPBrokerLock();
567
642
 
568
643
   while ((entry = (QPBrokerEntry *)QueuePairList_GetHead(&qpBrokerList))) {
569
644
      QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp);
570
645
      VMCI_FreeKernelMem(entry, sizeof *entry);
571
646
   }
572
647
 
573
 
   VMCIQPBroker_Unlock();
 
648
   VMCIQPBrokerUnlock();
574
649
   QueuePairList_Destroy(&qpBrokerList);
575
650
}
576
651
 
607
682
{
608
683
   return VMCIQPBrokerAllocInt(handle, peer, flags, privFlags,
609
684
                               produceSize, consumeSize,
610
 
                               pageStore, context, NULL);
611
 
}
612
 
 
613
 
 
614
 
/*
615
 
 *-----------------------------------------------------------------------------
616
 
 *
617
 
 * VMCIQPBrokerAllocInt --
618
 
 *
619
 
 *      QueuePair_Alloc for use when setting up queue pair endpoints
620
 
 *      on the host. Like QueuePair_Alloc, but returns a pointer to
621
 
 *      the QPBrokerEntry on success.
622
 
 *
623
 
 * Results:
624
 
 *      Success or failure.
625
 
 *
626
 
 * Side effects:
627
 
 *      Memory may be allocated.
628
 
 *
629
 
 *-----------------------------------------------------------------------------
630
 
 */
631
 
 
632
 
static int
633
 
VMCIQPBrokerAllocInt(VMCIHandle handle,             // IN
634
 
                     VMCIId peer,                   // IN
635
 
                     uint32 flags,                  // IN
636
 
                     VMCIPrivilegeFlags privFlags,  // IN
637
 
                     uint64 produceSize,            // IN
638
 
                     uint64 consumeSize,            // IN
639
 
                     QueuePairPageStore *pageStore, // IN/OUT
640
 
                     VMCIContext *context,          // IN: Caller
641
 
                     QPBrokerEntry **ent)           // OUT
642
 
{
643
 
   QPBrokerEntry *entry = NULL;
644
 
   int result;
645
 
   const VMCIId contextId = VMCIContext_GetId(context);
646
 
   Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
647
 
 
648
 
   if (VMCI_HANDLE_INVALID(handle) ||
649
 
       (flags & ~VMCI_QP_ALL_FLAGS) ||
650
 
       (isLocal && (!vmkernel || contextId != VMCI_HOST_CONTEXT_ID ||
651
 
                     handle.context != contextId)) ||
652
 
       !(produceSize || consumeSize) ||
653
 
       !context || contextId == VMCI_INVALID_ID ||
654
 
       handle.context == VMCI_INVALID_ID) {
655
 
      return VMCI_ERROR_INVALID_ARGS;
656
 
   }
657
 
 
658
 
#ifdef VMKERNEL
659
 
   if (!pageStore || (!pageStore->shared && !isLocal)) {
660
 
      return VMCI_ERROR_INVALID_ARGS;
661
 
   }
662
 
#else
663
 
   /*
664
 
    * On hosted, pageStore can be NULL if the caller doesn't want the
665
 
    * information
666
 
    */
667
 
   if (pageStore && !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore)) {
668
 
      return VMCI_ERROR_INVALID_ARGS;
669
 
   }
670
 
#endif // VMKERNEL
671
 
 
672
 
 
673
 
   /*
674
 
    * In the initial argument check, we ensure that non-vmkernel hosts
675
 
    * are not allowed to create local queue pairs.
676
 
    */
677
 
 
678
 
   ASSERT(vmkernel || !isLocal);
679
 
 
680
 
   if (!isLocal && VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
681
 
      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) already attached to queue pair "
682
 
                         "(handle=0x%x:0x%x).\n",
683
 
                         contextId, handle.context, handle.resource));
684
 
      result = VMCI_ERROR_ALREADY_EXISTS;
685
 
      goto out;
686
 
   }
687
 
 
688
 
   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
689
 
   if (!entry) { /* Create case. */
690
 
      /*
691
 
       * Do not create if the caller asked not to.
692
 
       */
693
 
 
694
 
      if (flags & VMCI_QPFLAG_ATTACH_ONLY) {
695
 
         result = VMCI_ERROR_NOT_FOUND;
696
 
         goto out;
697
 
      }
698
 
 
699
 
      /*
700
 
       * Creator's context ID should match handle's context ID or the creator
701
 
       * must allow the context in handle's context ID as the "peer".
702
 
       */
703
 
 
704
 
      if (handle.context != contextId && handle.context != peer) {
705
 
         result = VMCI_ERROR_NO_ACCESS;
706
 
         goto out;
707
 
      }
708
 
 
709
 
      /*
710
 
       * Check if we should allow this QueuePair connection.
711
 
       */
712
 
 
713
 
      if (QueuePairDenyConnection(contextId, peer)) {
714
 
         result = VMCI_ERROR_NO_ACCESS;
715
 
         goto out;
716
 
      }
717
 
 
718
 
      entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_ATOMIC);
719
 
      if (!entry) {
720
 
         result = VMCI_ERROR_NO_MEM;
721
 
         goto out;
722
 
      }
723
 
 
724
 
      memset(entry, 0, sizeof *entry);
725
 
      entry->qp.handle = handle;
726
 
      entry->qp.peer = peer;
727
 
      entry->qp.flags = flags;
728
 
      entry->qp.produceSize = produceSize;
729
 
      entry->qp.consumeSize = consumeSize;
730
 
      entry->qp.refCount = 1;
731
 
      entry->createId = contextId;
732
 
      entry->attachId = VMCI_INVALID_ID;
733
 
      entry->pageStoreSet = FALSE;
734
 
      entry->allowAttach = TRUE;
735
 
      entry->requireTrustedAttach =
736
 
         (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) ? TRUE : FALSE;
737
 
      entry->createdByTrusted =
738
 
         (privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED) ? TRUE : FALSE;
739
 
 
740
 
#ifndef VMKERNEL
741
 
      {
742
 
         uint64 numProducePages;
743
 
         uint64 numConsumePages;
744
 
 
745
 
         entry->produceQ = VMCIHost_AllocQueue(produceSize);
746
 
         if (entry->produceQ == NULL) {
747
 
            result = VMCI_ERROR_NO_MEM;
748
 
            goto errorDealloc;
749
 
         }
750
 
 
751
 
         entry->consumeQ = VMCIHost_AllocQueue(consumeSize);
752
 
         if (entry->consumeQ == NULL) {
753
 
            result = VMCI_ERROR_NO_MEM;
754
 
            goto errorDealloc;
755
 
         }
756
 
 
757
 
         entry->attachInfo = VMCI_AllocKernelMem(sizeof *entry->attachInfo,
758
 
                                                 VMCI_MEMORY_NORMAL);
759
 
         if (entry->attachInfo == NULL) {
760
 
            result = VMCI_ERROR_NO_MEM;
761
 
            goto errorDealloc;
762
 
         }
763
 
         memset(entry->attachInfo, 0, sizeof *entry->attachInfo);
764
 
 
765
 
         VMCI_InitQueueMutex(entry->produceQ, entry->consumeQ);
766
 
 
767
 
         numProducePages = CEILING(produceSize, PAGE_SIZE) + 1;
768
 
         numConsumePages = CEILING(consumeSize, PAGE_SIZE) + 1;
769
 
 
770
 
         entry->attachInfo->numProducePages = numProducePages;
771
 
         entry->attachInfo->numConsumePages = numConsumePages;
772
 
      }
773
 
#endif /* !VMKERNEL */
774
 
 
775
 
      VMCIList_InitEntry(&entry->qp.listItem);
776
 
 
777
 
      QueuePairList_AddEntry(&qpBrokerList, &entry->qp);
778
 
      result = VMCI_SUCCESS_QUEUEPAIR_CREATE;
779
 
   } else { /* Attach case. */
780
 
 
781
 
      /*
782
 
       * Check for failure conditions.
783
 
       */
784
 
 
785
 
      if (isLocal) {
786
 
         if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) ||
787
 
             contextId != entry->createId) {
788
 
            result = VMCI_ERROR_INVALID_ARGS;
789
 
            goto out;
790
 
         }
791
 
      } else if (contextId == entry->createId || contextId == entry->attachId) {
792
 
         result = VMCI_ERROR_ALREADY_EXISTS;
793
 
         goto out;
794
 
      }
795
 
 
796
 
      /*
797
 
       * QueuePairs are create/destroy entities.  There's no notion of
798
 
       * disconnecting/re-attaching, so once a queue pair entry has
799
 
       * been attached to, no further attaches are allowed. This
800
 
       * guards against both re-attaching and attaching to a queue
801
 
       * pair that already has two peers.
802
 
       */
803
 
 
804
 
      if (!entry->allowAttach) {
805
 
         result = VMCI_ERROR_UNAVAILABLE;
806
 
         goto out;
807
 
      }
808
 
      ASSERT(entry->qp.refCount < 2);
809
 
      ASSERT(entry->attachId == VMCI_INVALID_ID);
810
 
 
811
 
      /*
812
 
       * If we are attaching from a restricted context then the queuepair
813
 
       * must have been created by a trusted endpoint.
814
 
       */
815
 
 
816
 
      if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
817
 
         if (!entry->createdByTrusted) {
818
 
            result = VMCI_ERROR_NO_ACCESS;
819
 
            goto out;
820
 
         }
821
 
      }
822
 
 
823
 
      /*
824
 
       * If we are attaching to a queuepair that was created by a restricted
825
 
       * context then we must be trusted.
826
 
       */
827
 
 
828
 
      if (entry->requireTrustedAttach) {
829
 
         if (!(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) {
830
 
            result = VMCI_ERROR_NO_ACCESS;
831
 
            goto out;
832
 
         }
833
 
      }
834
 
 
835
 
      /*
836
 
       * If the creator specifies VMCI_INVALID_ID in "peer" field, access
837
 
       * control check is not performed.
838
 
       */
839
 
 
840
 
      if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != contextId) {
841
 
         result = VMCI_ERROR_NO_ACCESS;
842
 
         goto out;
843
 
      }
844
 
 
845
 
#ifndef VMKERNEL
846
 
      /*
847
 
       * VMKernel doesn't need to check the capabilities because the
848
 
       * whole system is installed as the kernel and matching VMX.
849
 
       */
850
 
 
851
 
      if (entry->createId == VMCI_HOST_CONTEXT_ID) {
852
 
         /*
853
 
          * Do not attach if the caller doesn't support Host Queue Pairs
854
 
          * and a host created this queue pair.
855
 
          */
856
 
 
857
 
         if (!VMCIContext_SupportsHostQP(context)) {
858
 
            result = VMCI_ERROR_INVALID_RESOURCE;
859
 
            goto out;
860
 
         }
861
 
      } else if (contextId == VMCI_HOST_CONTEXT_ID) {
862
 
         VMCIContext *createContext;
863
 
         Bool supportsHostQP;
864
 
 
865
 
         /*
866
 
          * Do not attach a host to a user created queue pair if that
867
 
          * user doesn't support host queue pair end points.
868
 
          */
869
 
 
870
 
         createContext = VMCIContext_Get(entry->createId);
871
 
         supportsHostQP = VMCIContext_SupportsHostQP(createContext);
872
 
         VMCIContext_Release(createContext);
873
 
 
874
 
         if (!supportsHostQP) {
875
 
            result = VMCI_ERROR_INVALID_RESOURCE;
876
 
            goto out;
877
 
         }
878
 
      }
879
 
#endif // !VMKERNEL
880
 
 
881
 
      if (entry->qp.produceSize != consumeSize ||
882
 
          entry->qp.consumeSize != produceSize ||
883
 
          entry->qp.flags != (flags & ~VMCI_QPFLAG_ATTACH_ONLY)) {
884
 
         result = VMCI_ERROR_QUEUEPAIR_MISMATCH;
885
 
         goto out;
886
 
      }
887
 
 
888
 
      /*
889
 
       * On VMKERNEL (e.g., ESX) we don't allow an attach until
890
 
       * the page store information has been set.
891
 
       *
892
 
       * However, on hosted products we support an attach to a
893
 
       * QueuePair that hasn't had its page store established yet.  In
894
 
       * fact, that's how a VMX guest will approach a host-created
895
 
       * QueuePair.  After the VMX guest does the attach, VMX will
896
 
       * receive the CREATE status code to indicate that it should
897
 
       * create the page files for the QueuePair contents.  It will
898
 
       * then issue a separate call down to set the page store.  That
899
 
       * will complete the attach case.
900
 
       */
901
 
      if (vmkernel && !entry->pageStoreSet) {
902
 
         result = VMCI_ERROR_QUEUEPAIR_NOTSET;
903
 
         goto out;
904
 
      }
905
 
 
906
 
      /*
907
 
       * Check if we should allow this QueuePair connection.
908
 
       */
909
 
 
910
 
      if (QueuePairDenyConnection(contextId, entry->createId)) {
911
 
         result = VMCI_ERROR_NO_ACCESS;
912
 
         goto out;
913
 
      }
914
 
 
915
 
#ifdef VMKERNEL
916
 
      pageStore->store = entry->store.store;
917
 
#else
918
 
      if (pageStore && entry->pageStoreSet) {
919
 
         ASSERT(entry->producePageFile[0] && entry->consumePageFile[0]);
920
 
         if (pageStore->producePageFileSize < sizeof entry->consumePageFile) {
921
 
            result = VMCI_ERROR_NO_MEM;
922
 
            goto out;
923
 
         }
924
 
         if (pageStore->consumePageFileSize < sizeof entry->producePageFile) {
925
 
            result = VMCI_ERROR_NO_MEM;
926
 
            goto out;
927
 
         }
928
 
 
929
 
         if (pageStore->user) {
930
 
            if (VMCI_CopyToUser(pageStore->producePageFile,
931
 
                                entry->consumePageFile,
932
 
                                sizeof entry->consumePageFile)) {
933
 
               result = VMCI_ERROR_GENERIC;
934
 
               goto out;
935
 
            }
936
 
 
937
 
            if (VMCI_CopyToUser(pageStore->consumePageFile,
938
 
                                entry->producePageFile,
939
 
                                sizeof entry->producePageFile)) {
940
 
               result = VMCI_ERROR_GENERIC;
941
 
               goto out;
942
 
            }
943
 
         } else {
944
 
            memcpy(VMCIVA64ToPtr(pageStore->producePageFile),
945
 
                   entry->consumePageFile,
946
 
                   sizeof entry->consumePageFile);
947
 
            memcpy(VMCIVA64ToPtr(pageStore->consumePageFile),
948
 
                   entry->producePageFile,
949
 
                   sizeof entry->producePageFile);
950
 
         }
951
 
      }
952
 
#endif // VMKERNEL
953
 
 
954
 
      /*
955
 
       * We only send notification if the other end of the QueuePair
956
 
       * is not the host (in hosted products).  In the case that a
957
 
       * host created the QueuePair, we'll send notification when the
958
 
       * guest issues the SetPageStore() (see next function).  The
959
 
       * reason is that the host can't use the QueuePair until the
960
 
       * SetPageStore() is complete.
961
 
       *
962
 
       * Note that in ESX we always send the notification now
963
 
       * because the host can begin to enqueue immediately.
964
 
       */
965
 
 
966
 
      if (vmkernel || entry->createId != VMCI_HOST_CONTEXT_ID) {
967
 
         result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
968
 
         if (result < VMCI_SUCCESS) {
969
 
            goto out;
970
 
         }
971
 
      }
972
 
 
973
 
      entry->attachId = contextId;
974
 
      entry->qp.refCount++;
975
 
      entry->allowAttach = FALSE;
976
 
 
977
 
      /*
978
 
       * Default response to an attach is _ATTACH.  However, if a host
979
 
       * created the QueuePair then we're a guest (because
980
 
       * host-to-host isn't supported).  And thus, the guest's VMX
981
 
       * needs to create the backing for the port.  So, we send up a
982
 
       * _CREATE response.
983
 
       */
984
 
 
985
 
      if (!vmkernel && entry->createId == VMCI_HOST_CONTEXT_ID) {
986
 
         result = VMCI_SUCCESS_QUEUEPAIR_CREATE;
987
 
      } else {
988
 
         result = VMCI_SUCCESS_QUEUEPAIR_ATTACH;
989
 
      }
990
 
   }
991
 
 
992
 
#ifndef VMKERNEL
993
 
   goto out;
994
 
 
995
 
   /*
996
 
    * Cleanup is only necessary on hosted
997
 
    */
998
 
 
999
 
errorDealloc:
1000
 
   if (entry->produceQ != NULL) {
1001
 
      VMCI_FreeKernelMem(entry->produceQ, sizeof *entry->produceQ);
1002
 
   }
1003
 
   if (entry->consumeQ != NULL) {
1004
 
      VMCI_FreeKernelMem(entry->consumeQ, sizeof *entry->consumeQ);
1005
 
   }
1006
 
   if (entry->attachInfo != NULL) {
1007
 
      VMCI_FreeKernelMem(entry->attachInfo, sizeof *entry->attachInfo);
1008
 
   }
1009
 
   VMCI_FreeKernelMem(entry, sizeof *entry);
1010
 
#endif // !VMKERNEL
1011
 
 
1012
 
out:
1013
 
   if (result >= VMCI_SUCCESS) {
1014
 
      ASSERT(entry);
1015
 
      if (ent != NULL) {
1016
 
         *ent = entry;
1017
 
      }
1018
 
 
1019
 
      /*
1020
 
       * When attaching to local queue pairs, the context already has
1021
 
       * an entry tracking the queue pair, so don't add another one.
1022
 
       */
1023
 
 
1024
 
      if (!isLocal || result == VMCI_SUCCESS_QUEUEPAIR_CREATE) {
1025
 
         ASSERT(!VMCIHandleArray_HasEntry(context->queuePairArray, handle));
1026
 
         VMCIHandleArray_AppendEntry(&context->queuePairArray, handle);
1027
 
      } else {
1028
 
         ASSERT(VMCIHandleArray_HasEntry(context->queuePairArray, handle));
1029
 
      }
1030
 
   }
1031
 
   return result;
1032
 
}
1033
 
 
1034
 
 
1035
 
/*
1036
 
 *-----------------------------------------------------------------------------
1037
 
 *
1038
 
 * VMCIQPBroker_SetPageStore --
1039
 
 *
1040
 
 *      The creator of a queue pair uses this to regsiter the page
1041
 
 *      store for a given queue pair.  Assumes that the queue pair
1042
 
 *      broker lock is held.
1043
 
 *
1044
 
 *      Note now that sometimes the client that attaches to a queue
1045
 
 *      pair will set the page store.  This happens on hosted products
1046
 
 *      because the host doesn't have a mechanism for creating the
1047
 
 *      backing memory for queue contents.  ESX does and so this is a
1048
 
 *      moot point there.  For example, note that in
1049
 
 *      VMCIQPBrokerAllocInt() an attaching guest receives the _CREATE
1050
 
 *      result code (instead of _ATTACH) on hosted products only, not
1051
 
 *      on VMKERNEL.
1052
 
 *
1053
 
 *      As a result, this routine now always creates the host
1054
 
 *      information even if the queue pair is only used by guests.  At
1055
 
 *      the time a guest creates a queue pair it doesn't know if a
1056
 
 *      host or guest will attach.  So, the host information always
1057
 
 *      has to be created.
1058
 
 *
1059
 
 * Results:
1060
 
 *      Success or failure.
1061
 
 *
1062
 
 * Side effects:
1063
 
 *      None.
1064
 
 *
1065
 
 *-----------------------------------------------------------------------------
1066
 
 */
1067
 
 
1068
 
int
1069
 
VMCIQPBroker_SetPageStore(VMCIHandle handle,             // IN
1070
 
                          QueuePairPageStore *pageStore, // IN
1071
 
                          VMCIContext *context)          // IN: Caller
1072
 
{
1073
 
   QPBrokerEntry *entry;
1074
 
   int result;
1075
 
   const VMCIId contextId = VMCIContext_GetId(context);
1076
 
#ifndef VMKERNEL
1077
 
   QueuePairPageStore normalizedPageStore;
1078
 
#endif
1079
 
 
1080
 
   if (VMCI_HANDLE_INVALID(handle) || !pageStore ||
1081
 
       !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore) ||
1082
 
       !context || contextId == VMCI_INVALID_ID) {
1083
 
      return VMCI_ERROR_INVALID_ARGS;
1084
 
   }
1085
 
 
1086
 
   if (!VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
1087
 
      VMCI_WARNING((LGPFX"Context (ID=0x%x) not attached to queue pair "
1088
 
                    "(handle=0x%x:0x%x).\n", contextId, handle.context,
1089
 
                    handle.resource));
1090
 
      result = VMCI_ERROR_NOT_FOUND;
1091
 
      goto out;
1092
 
   }
1093
 
 
1094
 
#ifndef VMKERNEL
1095
 
   /*
1096
 
    * If the client supports Host QueuePairs then it must provide the
1097
 
    * UVA's of the mmap()'d files backing the QueuePairs.
1098
 
    */
1099
 
 
1100
 
   if (VMCIContext_SupportsHostQP(context) &&
1101
 
       (pageStore->producePageUVA == 0 ||
1102
 
        pageStore->consumePageUVA == 0)) {
1103
 
      return VMCI_ERROR_INVALID_ARGS;
1104
 
   }
1105
 
#endif // !VMKERNEL
1106
 
 
1107
 
   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
1108
 
   if (!entry) {
1109
 
      result = VMCI_ERROR_NOT_FOUND;
1110
 
      goto out;
1111
 
   }
1112
 
 
1113
 
   /*
1114
 
    * If I'm the owner then I can set the page store.
1115
 
    *
1116
 
    * Or, if a host created the QueuePair and I'm the attached peer
1117
 
    * then I can set the page store.
1118
 
    */
1119
 
 
1120
 
   if (entry->createId != contextId &&
1121
 
       (entry->createId != VMCI_HOST_CONTEXT_ID ||
1122
 
        entry->attachId != contextId)) {
1123
 
      result = VMCI_ERROR_QUEUEPAIR_NOTOWNER;
1124
 
      goto out;
1125
 
   }
1126
 
   if (entry->pageStoreSet) {
1127
 
      result = VMCI_ERROR_UNAVAILABLE;
1128
 
      goto out;
1129
 
   }
1130
 
#ifdef VMKERNEL
1131
 
   entry->store = *pageStore;
1132
 
#else
1133
 
   /*
1134
 
    * Normalize the page store information from the point of view of
1135
 
    * the VMX process with respect to the QueuePair.  If VMX has
1136
 
    * attached to a host-created QueuePair and is passing down
1137
 
    * PageStore information then we must switch the produce/consume
1138
 
    * queue information before applying it to the QueuePair.
1139
 
    *
1140
 
    * In other words, the QueuePair structure (entry->state) is
1141
 
    * oriented with respect to the host that created it.  However, VMX
1142
 
    * is sending down information relative to its view of the world
1143
 
    * which is opposite of the host's.
1144
 
    */
1145
 
 
1146
 
   if (entry->createId == contextId) {
1147
 
      normalizedPageStore.producePageFile = pageStore->producePageFile;
1148
 
      normalizedPageStore.consumePageFile = pageStore->consumePageFile;
1149
 
      normalizedPageStore.producePageFileSize = pageStore->producePageFileSize;
1150
 
      normalizedPageStore.consumePageFileSize = pageStore->consumePageFileSize;
1151
 
      normalizedPageStore.producePageUVA = pageStore->producePageUVA;
1152
 
      normalizedPageStore.consumePageUVA = pageStore->consumePageUVA;
1153
 
   } else {
1154
 
      normalizedPageStore.producePageFile = pageStore->consumePageFile;
1155
 
      normalizedPageStore.consumePageFile = pageStore->producePageFile;
1156
 
      normalizedPageStore.producePageFileSize = pageStore->consumePageFileSize;
1157
 
      normalizedPageStore.consumePageFileSize = pageStore->producePageFileSize;
1158
 
      normalizedPageStore.producePageUVA = pageStore->consumePageUVA;
1159
 
      normalizedPageStore.consumePageUVA = pageStore->producePageUVA;
1160
 
   }
1161
 
 
1162
 
   if (normalizedPageStore.producePageFileSize > sizeof entry->producePageFile) {
1163
 
      result = VMCI_ERROR_NO_MEM;
1164
 
       goto out;
1165
 
   }
1166
 
   if (normalizedPageStore.consumePageFileSize > sizeof entry->consumePageFile) {
1167
 
      result = VMCI_ERROR_NO_MEM;
1168
 
      goto out;
1169
 
   }
1170
 
   if (pageStore->user) {
1171
 
      if (VMCI_CopyFromUser(entry->producePageFile,
1172
 
                            normalizedPageStore.producePageFile,
1173
 
                            (size_t)normalizedPageStore.producePageFileSize)) {
1174
 
         result = VMCI_ERROR_GENERIC;
1175
 
         goto out;
1176
 
      }
1177
 
 
1178
 
      if (VMCI_CopyFromUser(entry->consumePageFile,
1179
 
                            normalizedPageStore.consumePageFile,
1180
 
                            (size_t)normalizedPageStore.consumePageFileSize)) {
1181
 
         result = VMCI_ERROR_GENERIC;
1182
 
         goto out;
1183
 
      }
1184
 
   } else {
1185
 
      memcpy(entry->consumePageFile,
1186
 
             VMCIVA64ToPtr(normalizedPageStore.consumePageFile),
1187
 
             (size_t)normalizedPageStore.consumePageFileSize);
1188
 
      memcpy(entry->producePageFile,
1189
 
             VMCIVA64ToPtr(normalizedPageStore.producePageFile),
1190
 
             (size_t)normalizedPageStore.producePageFileSize);
1191
 
   }
1192
 
 
1193
 
   /*
1194
 
    * Copy the data into the attachInfo structure
1195
 
    */
1196
 
 
1197
 
   memcpy(&entry->attachInfo->producePageFile[0],
1198
 
          &entry->producePageFile[0],
1199
 
          (size_t)normalizedPageStore.producePageFileSize);
1200
 
   memcpy(&entry->attachInfo->consumePageFile[0],
1201
 
          &entry->consumePageFile[0],
1202
 
          (size_t)normalizedPageStore.consumePageFileSize);
1203
 
 
1204
 
   /*
1205
 
    * NOTE: The UVAs that follow may be 0.  In this case an older VMX has
1206
 
    * issued a SetPageFile call without mapping the backing files for the
1207
 
    * queue contents.  The result of this is that the queue pair cannot
1208
 
    * be connected by host.
1209
 
    */
1210
 
 
1211
 
   entry->attachInfo->produceBuffer = normalizedPageStore.producePageUVA;
1212
 
   entry->attachInfo->consumeBuffer = normalizedPageStore.consumePageUVA;
1213
 
 
1214
 
   if (VMCIContext_SupportsHostQP(context)) {
1215
 
      result = VMCIHost_GetUserMemory(entry->attachInfo,
1216
 
                                      entry->produceQ,
1217
 
                                      entry->consumeQ);
1218
 
 
1219
 
      if (result < VMCI_SUCCESS) {
1220
 
         goto out;
1221
 
      }
1222
 
   }
1223
 
#endif // VMKERNEL
1224
 
 
1225
 
   /*
1226
 
    * In the event that the QueuePair was created by a host in a
1227
 
    * hosted kernel, then we send notification now that the QueuePair
1228
 
    * contents backing files are attached to the Queues.  Note in
1229
 
    * VMCIQPBrokerAllocInt(), above, we skipped this step when the
1230
 
    * creator was a host (on hosted).
1231
 
    */
1232
 
 
1233
 
   if (!vmkernel && entry->createId == VMCI_HOST_CONTEXT_ID) {
1234
 
      result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
1235
 
      if (result < VMCI_SUCCESS) {
1236
 
         goto out;
1237
 
      }
1238
 
   }
1239
 
 
1240
 
   entry->pageStoreSet = TRUE;
1241
 
   result = VMCI_SUCCESS;
1242
 
 
1243
 
out:
1244
 
   return result;
1245
 
}
1246
 
 
1247
 
 
1248
 
/*
1249
 
 *-----------------------------------------------------------------------------
1250
 
 *
1251
 
 * VMCIQPBroker_Detach --
1252
 
 *
1253
 
 *      Informs the VMCI queue pair broker that a context has detached
1254
 
 *      from a given QueuePair handle.  Assumes that the queue pair
1255
 
 *      broker lock is held.  If the "detach" input parameter is
1256
 
 *      FALSE, the queue pair entry is not removed from the list of
1257
 
 *      queue pairs registered with the queue pair broker, and the
1258
 
 *      context is not detached from the given handle.  If "detach" is
1259
 
 *      TRUE, the detach operation really happens.  With "detach" set
1260
 
 *      to FALSE, the caller can query if the "actual" detach
1261
 
 *      operation would succeed or not.  The return value from this
1262
 
 *      function remains the same irrespective of the value of the
1263
 
 *      boolean "detach".
1264
 
 *
1265
 
 *      Also note that the result code for a VM detaching from a
1266
 
 *      VM-host queue pair is always VMCI_SUCCESS_LAST_DETACH.  This
1267
 
 *      is so that VMX can unlink the backing files.  On the host side
1268
 
 *      the files are either locked (Mac OS/Linux) or the contents are
1269
 
 *      saved (Windows).
1270
 
 *
1271
 
 * Results:
1272
 
 *      Success or failure.
1273
 
 *
1274
 
 * Side effects:
1275
 
 *      None.
1276
 
 *
1277
 
 *-----------------------------------------------------------------------------
1278
 
 */
1279
 
 
1280
 
int
1281
 
VMCIQPBroker_Detach(VMCIHandle  handle,   // IN
1282
 
                    VMCIContext *context, // IN
1283
 
                    Bool detach)          // IN: Really detach?
1284
 
{
1285
 
   QPBrokerEntry *entry;
1286
 
   int result;
1287
 
   const VMCIId contextId = VMCIContext_GetId(context);
1288
 
   VMCIId peerId;
1289
 
   Bool isLocal = FALSE;
1290
 
 
1291
 
   if (VMCI_HANDLE_INVALID(handle) ||
1292
 
       !context || contextId == VMCI_INVALID_ID) {
1293
 
      return VMCI_ERROR_INVALID_ARGS;
1294
 
   }
1295
 
 
1296
 
   if (!VMCIHandleArray_HasEntry(context->queuePairArray, handle)) {
1297
 
      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
1298
 
                         "(handle=0x%x:0x%x).\n",
1299
 
                         contextId, handle.context, handle.resource));
1300
 
      result = VMCI_ERROR_NOT_FOUND;
1301
 
      goto out;
1302
 
   }
1303
 
 
1304
 
   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
1305
 
   if (!entry) {
1306
 
      result = VMCI_ERROR_NOT_FOUND;
1307
 
      goto out;
1308
 
   }
1309
 
 
1310
 
   isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
1311
 
 
1312
 
   ASSERT(vmkernel || !isLocal);
1313
 
 
1314
 
   if (contextId != entry->createId && contextId != entry->attachId) {
1315
 
      result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
1316
 
      goto out;
1317
 
   }
1318
 
 
1319
 
   if (contextId == entry->createId) {
1320
 
      peerId = entry->attachId;
1321
 
   } else {
1322
 
      peerId = entry->createId;
1323
 
   }
1324
 
 
1325
 
   if (!detach) {
1326
 
      /* Do not update the queue pair entry. */
1327
 
 
1328
 
      ASSERT(entry->qp.refCount == 1 || entry->qp.refCount == 2);
1329
 
 
1330
 
      if (entry->qp.refCount == 1 ||
1331
 
          (!vmkernel && peerId == VMCI_HOST_CONTEXT_ID)) {
1332
 
         result = VMCI_SUCCESS_LAST_DETACH;
1333
 
      } else {
1334
 
         result = VMCI_SUCCESS;
1335
 
      }
1336
 
 
1337
 
      goto out;
1338
 
   }
1339
 
 
1340
 
   if (contextId == entry->createId) {
1341
 
      entry->createId = VMCI_INVALID_ID;
1342
 
   } else {
1343
 
      entry->attachId = VMCI_INVALID_ID;
1344
 
   }
1345
 
   entry->qp.refCount--;
1346
 
 
1347
 
#ifdef _WIN32
1348
 
   /*
1349
 
    * If the caller detaching is a usermode process (e.g., VMX), then
1350
 
    * we must detach the mappings now.  On Windows.
1351
 
    *
1352
 
    * VMCIHost_SaveProduceQ() will save the guest's produceQ so that
1353
 
    * the host can pick up the data after the guest is gone.
1354
 
    *
1355
 
    * We save the ProduceQ whenever the guest detaches (even if VMX
1356
 
    * continues to run).  If we didn't do this, then we'd have the
1357
 
    * problem of finding and releasing the memory when the client goes
1358
 
    * away because we won't be able to find the client in the list of
1359
 
    * QueuePair entries.  The detach code path (has already) set the
1360
 
    * contextId for detached end-point to VMCI_INVALID_ID.  (See just
1361
 
    * a few lines above where that happens.)  Sure, we could fix that,
1362
 
    * and then we could look at all entries finding ones where the
1363
 
    * contextId of either creator or attach matches the going away
1364
 
    * context's Id.  But, if we just copy out the guest's produceQ
1365
 
    * -always- then we reduce the logic changes elsewhere.
1366
 
    */
1367
 
 
1368
 
   /*
1369
 
    * Some example paths through this code:
1370
 
    *
1371
 
    * Guest-to-guest: the code will call ReleaseUserMemory() once when
1372
 
    * the first guest detaches.  And then a second time when the
1373
 
    * second guest detaches.  That's OK.  Nobody is using the user
1374
 
    * memory (because there is no host attached) and
1375
 
    * ReleaseUserMemory() tracks its resources.
1376
 
    *
1377
 
    * Host detaches first: the code will not call anything because
1378
 
    * contextId == VMCI_HOST_CONTEXT_ID and because (in the second if
1379
 
    * () clause below) refCount > 0.
1380
 
    *
1381
 
    * Guest detaches second: the first if clause, below, will not be
1382
 
    * taken because refCount is already 0.  The second if () clause
1383
 
    * (below) will be taken and it will simply call
1384
 
    * ReleaseUserMemory().
1385
 
    *
1386
 
    * Guest detaches first: the code will call SaveProduceQ().
1387
 
    *
1388
 
    * Host detaches second: the code will call ReleaseUserMemory()
1389
 
    * which will free the kernel allocated Q memory.
1390
 
    */
1391
 
 
1392
 
   if (entry->pageStoreSet &&
1393
 
       contextId != VMCI_HOST_CONTEXT_ID &&
1394
 
       VMCIContext_SupportsHostQP(context) &&
1395
 
       entry->qp.refCount) {
1396
 
      /*
1397
 
       * It's important to pass down produceQ and consumeQ in the
1398
 
       * correct order because the produceQ that is to be saved is the
1399
 
       * guest's, so we have to be sure that the routine sees the
1400
 
       * guest's produceQ as (in this case) the first Q parameter.
1401
 
       */
1402
 
 
1403
 
      if (entry->attachId == VMCI_HOST_CONTEXT_ID) {
1404
 
         VMCIHost_SaveProduceQ(entry->attachInfo,
1405
 
                               entry->produceQ,
1406
 
                               entry->consumeQ,
1407
 
                               entry->qp.produceSize);
1408
 
      } else if (entry->createId == VMCI_HOST_CONTEXT_ID) {
1409
 
         VMCIHost_SaveProduceQ(entry->attachInfo,
1410
 
                               entry->consumeQ,
1411
 
                               entry->produceQ,
1412
 
                               entry->qp.consumeSize);
1413
 
      } else {
1414
 
         VMCIHost_ReleaseUserMemory(entry->attachInfo,
1415
 
                                    entry->produceQ,
1416
 
                                    entry->consumeQ);
1417
 
      }
1418
 
   }
1419
 
#endif // _WIN32
1420
 
 
1421
 
   if (!entry->qp.refCount) {
1422
 
      QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp);
1423
 
 
1424
 
#ifndef VMKERNEL
1425
 
      if (entry->pageStoreSet &&
1426
 
          VMCIContext_SupportsHostQP(context)) {
1427
 
         VMCIHost_ReleaseUserMemory(entry->attachInfo,
1428
 
                                    entry->produceQ,
1429
 
                                    entry->consumeQ);
1430
 
      }
1431
 
      if (entry->attachInfo) {
1432
 
         VMCI_FreeKernelMem(entry->attachInfo, sizeof *entry->attachInfo);
1433
 
      }
1434
 
      if (entry->produceQ) {
1435
 
         VMCI_FreeKernelMem(entry->produceQ, sizeof *entry->produceQ);
1436
 
      }
1437
 
      if (entry->consumeQ) {
1438
 
         VMCI_FreeKernelMem(entry->consumeQ, sizeof *entry->consumeQ);
1439
 
      }
1440
 
#endif // !VMKERNEL
1441
 
 
1442
 
      VMCI_FreeKernelMem(entry, sizeof *entry);
1443
 
      result = VMCI_SUCCESS_LAST_DETACH;
1444
 
   } else {
1445
 
      /*
1446
 
       * XXX: If we ever allow the creator to detach and attach again
1447
 
       * to the same queue pair, we need to handle the mapping of the
1448
 
       * shared memory region in vmkernel differently. Currently, we
1449
 
       * assume that an attaching VM always needs to swap the two
1450
 
       * queues.
1451
 
       */
1452
 
 
1453
 
      ASSERT(peerId != VMCI_INVALID_ID);
1454
 
      QueuePairNotifyPeer(FALSE, handle, contextId, peerId);
1455
 
      if (!vmkernel && peerId == VMCI_HOST_CONTEXT_ID) {
1456
 
         result = VMCI_SUCCESS_LAST_DETACH;
1457
 
      } else {
1458
 
         result = VMCI_SUCCESS;
1459
 
      }
1460
 
   }
1461
 
 
1462
 
out:
1463
 
   if (result >= VMCI_SUCCESS && detach) {
1464
 
      if (!isLocal || result == VMCI_SUCCESS_LAST_DETACH) {
1465
 
         VMCIHandleArray_RemoveEntry(context->queuePairArray, handle);
1466
 
      }
1467
 
   }
1468
 
   return result;
 
685
                               pageStore, context, NULL, NULL,
 
686
                               NULL, NULL);
1469
687
}
1470
688
 
1471
689
 
1513
731
   /*
1514
732
    * In VMCIContext_EnqueueDatagram() we enforce the upper limit on number of
1515
733
    * pending events from the hypervisor to a given VM otherwise a rogue VM
1516
 
    * could do arbitrary number of attached and detaches causing memory
 
734
    * could do an arbitrary number of attach and detach operations causing memory
1517
735
    * pressure in the host kernel.
1518
736
   */
1519
737
 
1520
738
   /* Clear out any garbage. */
1521
 
   memset(eMsg, 0, sizeof *eMsg + sizeof *evPayload);
 
739
   memset(eMsg, 0, sizeof buf);
1522
740
 
1523
741
   eMsg->hdr.dst = VMCI_MAKE_HANDLE(peerId, VMCI_EVENT_HANDLER);
1524
742
   eMsg->hdr.src = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
1541
759
   return rv;
1542
760
}
1543
761
 
1544
 
#if !defined(VMKERNEL)
1545
762
 
1546
763
/*
1547
764
 *----------------------------------------------------------------------
1568
785
                           uint64 consumeSize,           // IN
1569
786
                           VMCIId peer,                  // IN
1570
787
                           uint32 flags,                 // IN
1571
 
                           VMCIPrivilegeFlags privFlags) // IN
 
788
                           VMCIPrivilegeFlags privFlags, // IN
 
789
                           VMCIEventReleaseCB wakeupCB,  // IN
 
790
                           void *clientData)             // IN
1572
791
{
1573
792
   VMCIContext *context;
 
793
   QPBrokerEntry *entry;
1574
794
   int result;
1575
 
   QPBrokerEntry *entry;
1576
 
 
1577
 
   result = VMCI_SUCCESS;
 
795
   Bool swap;
1578
796
 
1579
797
   if (VMCI_HANDLE_INVALID(*handle)) {
1580
798
      VMCIId resourceID = VMCIResource_GetID(VMCI_HOST_CONTEXT_ID);
1588
806
   ASSERT(context);
1589
807
 
1590
808
   entry = NULL;
1591
 
   VMCIQPBroker_Lock();
1592
809
   result = VMCIQPBrokerAllocInt(*handle, peer, flags, privFlags, produceSize,
1593
 
                                 consumeSize, NULL, context, &entry);
1594
 
 
1595
 
   if (result >= VMCI_SUCCESS) {
1596
 
      ASSERT(entry != NULL);
1597
 
 
1598
 
      if (entry->createId == VMCI_HOST_CONTEXT_ID) {
 
810
                                 consumeSize, NULL, context, wakeupCB, clientData,
 
811
                                 &entry, &swap);
 
812
   if (result == VMCI_SUCCESS) {
 
813
      if (swap) {
 
814
         /*
 
815
          * If this is a local queue pair, the attacher will swap around produce
 
816
          * and consume queues.
 
817
          */
 
818
 
 
819
         *produceQ = entry->consumeQ;
 
820
         *consumeQ = entry->produceQ;
 
821
      } else {
1599
822
         *produceQ = entry->produceQ;
1600
823
         *consumeQ = entry->consumeQ;
1601
 
      } else {
1602
 
         *produceQ = entry->consumeQ;
1603
 
         *consumeQ = entry->produceQ;
1604
824
      }
1605
 
 
1606
 
      result = VMCI_SUCCESS;
1607
825
   } else {
1608
826
      *handle = VMCI_INVALID_HANDLE;
1609
827
      VMCI_DEBUG_LOG(4, (LGPFX"queue pair broker failed to alloc (result=%d).\n",
1610
828
                         result));
1611
829
   }
1612
 
 
1613
 
   VMCIQPBroker_Unlock();
1614
830
   VMCIContext_Release(context);
1615
831
   return result;
1616
832
}
1641
857
 
1642
858
   context = VMCIContext_Get(VMCI_HOST_CONTEXT_ID);
1643
859
 
1644
 
   VMCIQPBroker_Lock();
1645
 
   result = VMCIQPBroker_Detach(handle, context, TRUE);
1646
 
   VMCIQPBroker_Unlock();
 
860
   result = VMCIQPBroker_Detach(handle, context);
1647
861
 
1648
862
   VMCIContext_Release(context);
1649
863
   return result;
1653
867
/*
1654
868
 *-----------------------------------------------------------------------------
1655
869
 *
 
870
 * VMCIQPBrokerAllocInt --
 
871
 *
 
872
 *      QueuePair_Alloc for use when setting up queue pair endpoints
 
873
 *      on the host. Like QueuePair_Alloc, but returns a pointer to
 
874
 *      the QPBrokerEntry on success.
 
875
 *
 
876
 * Results:
 
877
 *      Success or failure.
 
878
 *
 
879
 * Side effects:
 
880
 *      Memory may be allocated.
 
881
 *
 
882
 *-----------------------------------------------------------------------------
 
883
 */
 
884
 
 
885
static int
 
886
VMCIQPBrokerAllocInt(VMCIHandle handle,             // IN
 
887
                     VMCIId peer,                   // IN
 
888
                     uint32 flags,                  // IN
 
889
                     VMCIPrivilegeFlags privFlags,  // IN
 
890
                     uint64 produceSize,            // IN
 
891
                     uint64 consumeSize,            // IN
 
892
                     QueuePairPageStore *pageStore, // IN/OUT
 
893
                     VMCIContext *context,          // IN: Caller
 
894
                     VMCIEventReleaseCB wakeupCB,   // IN
 
895
                     void *clientData,              // IN
 
896
                     QPBrokerEntry **ent,           // OUT
 
897
                     Bool *swap)                    // OUT: swap queues?
 
898
{
 
899
   const VMCIId contextId = VMCIContext_GetId(context);
 
900
   Bool create;
 
901
   QPBrokerEntry *entry;
 
902
   Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
 
903
   int result;
 
904
 
 
905
   if (VMCI_HANDLE_INVALID(handle) ||
 
906
       (flags & ~VMCI_QP_ALL_FLAGS) ||
 
907
       (isLocal && (!vmkernel || contextId != VMCI_HOST_CONTEXT_ID ||
 
908
                     handle.context != contextId)) ||
 
909
       !(produceSize || consumeSize) ||
 
910
       !context || contextId == VMCI_INVALID_ID ||
 
911
       handle.context == VMCI_INVALID_ID) {
 
912
      return VMCI_ERROR_INVALID_ARGS;
 
913
   }
 
914
 
 
915
   if (pageStore && !VMCI_QP_PAGESTORE_IS_WELLFORMED(pageStore)) {
 
916
      return VMCI_ERROR_INVALID_ARGS;
 
917
   }
 
918
 
 
919
   /*
 
920
    * In the initial argument check, we ensure that non-vmkernel hosts
 
921
    * are not allowed to create local queue pairs.
 
922
    */
 
923
 
 
924
   ASSERT(vmkernel || !isLocal);
 
925
 
 
926
   VMCIQPBrokerLock();
 
927
 
 
928
   if (!isLocal && VMCIContext_QueuePairExists(context, handle)) {
 
929
      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) already attached to queue pair "
 
930
                         "(handle=0x%x:0x%x).\n",
 
931
                         contextId, handle.context, handle.resource));
 
932
      VMCIQPBrokerUnlock();
 
933
      return VMCI_ERROR_ALREADY_EXISTS;
 
934
   }
 
935
 
 
936
   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
 
937
   if (!entry) {
 
938
      create = TRUE;
 
939
      result = VMCIQPBrokerCreate(handle, peer, flags, privFlags, produceSize,
 
940
                                  consumeSize, pageStore, context, wakeupCB,
 
941
                                  clientData, ent);
 
942
   } else {
 
943
      create = FALSE;
 
944
      result = VMCIQPBrokerAttach(entry, peer, flags, privFlags, produceSize,
 
945
                                  consumeSize, pageStore, context, wakeupCB,
 
946
                                  clientData, ent);
 
947
   }
 
948
 
 
949
   VMCIQPBrokerUnlock();
 
950
 
 
951
   if (swap) {
 
952
      *swap = (contextId == VMCI_HOST_CONTEXT_ID) && !(create && isLocal);
 
953
   }
 
954
 
 
955
   return result;
 
956
}
 
957
 
 
958
 
 
959
/*
 
960
 *-----------------------------------------------------------------------------
 
961
 *
 
962
 * VMCIQPBrokerCreate --
 
963
 *
 
964
 *      The first endpoint issuing a queue pair allocation will create the state
 
965
 *      of the queue pair in the queue pair broker.
 
966
 *
 
967
 *      If the creator is a guest, it will associate a VMX virtual address range
 
968
 *      with the queue pair as specified by the pageStore. For compatibility with
 
969
 *      older VMX'en, that would use a separate step to set the VMX virtual
 
970
 *      address range, the virtual address range can be registered later using
 
971
 *      VMCIQPBroker_SetPageStore. In that case, a pageStore of NULL should be
 
972
 *      used.
 
973
 *
 
974
 *      If the creator is the host, a pageStore of NULL should be used as well,
 
975
 *      since the host is not able to supply a page store for the queue pair.
 
976
 *
 
977
 *      For older VMX and host callers, the queue pair will be created in the
 
978
 *      VMCIQPB_CREATED_NO_MEM state, and for current VMX callers, it will be
 
979
 *      created in VMCOQPB_CREATED_MEM state.
 
980
 *
 
981
 * Results:
 
982
 *      VMCI_SUCCESS on success, appropriate error code otherwise.
 
983
 *
 
984
 * Side effects:
 
985
 *      Memory will be allocated, and pages may be pinned.
 
986
 *
 
987
 *-----------------------------------------------------------------------------
 
988
 */
 
989
 
 
990
static int
 
991
VMCIQPBrokerCreate(VMCIHandle handle,             // IN
 
992
                   VMCIId peer,                   // IN
 
993
                   uint32 flags,                  // IN
 
994
                   VMCIPrivilegeFlags privFlags,  // IN
 
995
                   uint64 produceSize,            // IN
 
996
                   uint64 consumeSize,            // IN
 
997
                   QueuePairPageStore *pageStore, // IN
 
998
                   VMCIContext *context,          // IN: Caller
 
999
                   VMCIEventReleaseCB wakeupCB,   // IN
 
1000
                   void *clientData,              // IN
 
1001
                   QPBrokerEntry **ent)           // OUT
 
1002
{
 
1003
   QPBrokerEntry *entry = NULL;
 
1004
   const VMCIId contextId = VMCIContext_GetId(context);
 
1005
   Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
 
1006
   int result;
 
1007
   uint64 guestProduceSize;
 
1008
   uint64 guestConsumeSize;
 
1009
 
 
1010
   /*
 
1011
    * Do not create if the caller asked not to.
 
1012
    */
 
1013
 
 
1014
   if (flags & VMCI_QPFLAG_ATTACH_ONLY) {
 
1015
      return VMCI_ERROR_NOT_FOUND;
 
1016
   }
 
1017
 
 
1018
   /*
 
1019
    * Creator's context ID should match handle's context ID or the creator
 
1020
    * must allow the context in handle's context ID as the "peer".
 
1021
    */
 
1022
 
 
1023
   if (handle.context != contextId && handle.context != peer) {
 
1024
      return VMCI_ERROR_NO_ACCESS;
 
1025
   }
 
1026
 
 
1027
   if (VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(peer)) {
 
1028
      return VMCI_ERROR_DST_UNREACHABLE;
 
1029
   }
 
1030
 
 
1031
   /*
 
1032
    * Creator's context ID for local queue pairs should match the
 
1033
    * peer, if a peer is specified.
 
1034
    */
 
1035
 
 
1036
   if (isLocal && peer != VMCI_INVALID_ID && contextId != peer) {
 
1037
      return VMCI_ERROR_NO_ACCESS;
 
1038
   }
 
1039
 
 
1040
   entry = VMCI_AllocKernelMem(sizeof *entry, VMCI_MEMORY_ATOMIC);
 
1041
   if (!entry) {
 
1042
      return VMCI_ERROR_NO_MEM;
 
1043
   }
 
1044
 
 
1045
   if (VMCIContext_GetId(context) == VMCI_HOST_CONTEXT_ID && !isLocal) {
 
1046
      /*
 
1047
       * The queue pair broker entry stores values from the guest
 
1048
       * point of view, so a creating host side endpoint should swap
 
1049
       * produce and consume values -- unless it is a local queue
 
1050
       * pair, in which case no swapping is necessary, since the local
 
1051
       * attacher will swap queues.
 
1052
       */
 
1053
 
 
1054
      guestProduceSize = consumeSize;
 
1055
      guestConsumeSize = produceSize;
 
1056
   } else {
 
1057
      guestProduceSize = produceSize;
 
1058
      guestConsumeSize = consumeSize;
 
1059
   }
 
1060
 
 
1061
   memset(entry, 0, sizeof *entry);
 
1062
   entry->qp.handle = handle;
 
1063
   entry->qp.peer = peer;
 
1064
   entry->qp.flags = flags;
 
1065
   entry->qp.produceSize = guestProduceSize;
 
1066
   entry->qp.consumeSize = guestConsumeSize;
 
1067
   entry->qp.refCount = 1;
 
1068
   entry->createId = contextId;
 
1069
   entry->attachId = VMCI_INVALID_ID;
 
1070
   entry->state = VMCIQPB_NEW;
 
1071
   entry->requireTrustedAttach =
 
1072
      (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) ? TRUE : FALSE;
 
1073
   entry->createdByTrusted =
 
1074
      (privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED) ? TRUE : FALSE;
 
1075
   entry->vmciPageFiles = FALSE;
 
1076
   entry->wakeupCB = wakeupCB;
 
1077
   entry->clientData = clientData;
 
1078
   entry->produceQ = VMCIHost_AllocQueue(guestProduceSize);
 
1079
   if (entry->produceQ == NULL) {
 
1080
      result = VMCI_ERROR_NO_MEM;
 
1081
      goto error;
 
1082
   }
 
1083
   entry->consumeQ = VMCIHost_AllocQueue(guestConsumeSize);
 
1084
   if (entry->consumeQ == NULL) {
 
1085
      result = VMCI_ERROR_NO_MEM;
 
1086
      goto error;
 
1087
   }
 
1088
 
 
1089
   VMCI_InitQueueMutex(entry->produceQ, entry->consumeQ);
 
1090
 
 
1091
   VMCIList_InitEntry(&entry->qp.listItem);
 
1092
 
 
1093
   if (isLocal) {
 
1094
      ASSERT(pageStore == NULL);
 
1095
 
 
1096
      entry->localMem = VMCI_AllocKernelMem(QPE_NUM_PAGES(entry->qp) * PAGE_SIZE,
 
1097
                                            VMCI_MEMORY_NONPAGED);
 
1098
      if (entry->localMem == NULL) {
 
1099
         result = VMCI_ERROR_NO_MEM;
 
1100
         goto error;
 
1101
      }
 
1102
      entry->state = VMCIQPB_CREATED_MEM;
 
1103
      entry->produceQ->qHeader = entry->localMem;
 
1104
      entry->consumeQ->qHeader =
 
1105
         (VMCIQueueHeader *)((uint8 *)entry->localMem +
 
1106
             (CEILING(entry->qp.produceSize, PAGE_SIZE) + 1) * PAGE_SIZE);
 
1107
      VMCIQueueHeader_Init(entry->produceQ->qHeader, handle);
 
1108
      VMCIQueueHeader_Init(entry->consumeQ->qHeader, handle);
 
1109
   } else if (pageStore) {
 
1110
      ASSERT(entry->createId != VMCI_HOST_CONTEXT_ID || isLocal);
 
1111
 
 
1112
      /*
 
1113
       * The VMX already initialized the queue pair headers, so no
 
1114
       * need for the kernel side to do that.
 
1115
       */
 
1116
 
 
1117
      result = VMCIHost_RegisterUserMemory(pageStore,
 
1118
                                           entry->produceQ,
 
1119
                                           entry->consumeQ);
 
1120
      if (result < VMCI_SUCCESS) {
 
1121
         goto error;
 
1122
      }
 
1123
      VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
 
1124
      entry->state = VMCIQPB_CREATED_MEM;
 
1125
   } else {
 
1126
      /*
 
1127
       * A create without a pageStore may be either a host side create (in which
 
1128
       * case we are waiting for the guest side to supply the memory) or an old
 
1129
       * style queue pair create (in which case we will expect a set page store
 
1130
       * call as the next step).
 
1131
       */
 
1132
 
 
1133
      entry->state = VMCIQPB_CREATED_NO_MEM;
 
1134
   }
 
1135
 
 
1136
   QueuePairList_AddEntry(&qpBrokerList, &entry->qp);
 
1137
   if (ent != NULL) {
 
1138
      *ent = entry;
 
1139
   }
 
1140
 
 
1141
   VMCIContext_QueuePairCreate(context, handle);
 
1142
 
 
1143
   return VMCI_SUCCESS;
 
1144
 
 
1145
error:
 
1146
   if (entry != NULL) {
 
1147
      if (entry->produceQ != NULL) {
 
1148
         VMCIHost_FreeQueue(entry->produceQ, guestProduceSize);
 
1149
      }
 
1150
      if (entry->consumeQ != NULL) {
 
1151
         VMCIHost_FreeQueue(entry->consumeQ, guestConsumeSize);
 
1152
      }
 
1153
      VMCI_FreeKernelMem(entry, sizeof *entry);
 
1154
   }
 
1155
   return result;
 
1156
}
 
1157
 
 
1158
 
 
1159
/*
 
1160
 *-----------------------------------------------------------------------------
 
1161
 *
 
1162
 * VMCIQPBrokerAttach --
 
1163
 *
 
1164
 *      The second endpoint issuing a queue pair allocation will attach to the
 
1165
 *      queue pair registered with the queue pair broker.
 
1166
 *
 
1167
 *      If the attacher is a guest, it will associate a VMX virtual address range
 
1168
 *      with the queue pair as specified by the pageStore. At this point, the
 
1169
 *      already attach host endpoint may start using the queue pair, and an
 
1170
 *      attach event is sent to it. For compatibility with older VMX'en, that
 
1171
 *      used a separate step to set the VMX virtual address range, the virtual
 
1172
 *      address range can be registered later using VMCIQPBroker_SetPageStore. In
 
1173
 *      that case, a pageStore of NULL should be used, and the attach event will
 
1174
 *      be generated once the actual page store has been set.
 
1175
 *
 
1176
 *      If the attacher is the host, a pageStore of NULL should be used as well,
 
1177
 *      since the page store information is already set by the guest.
 
1178
 *
 
1179
 *      For new VMX and host callers, the queue pair will be moved to the
 
1180
 *      VMCIQPB_ATTACHED_MEM state, and for older VMX callers, it will be
 
1181
 *      moved to the VMCOQPB_ATTACHED_NO_MEM state.
 
1182
 *
 
1183
 * Results:
 
1184
 *      VMCI_SUCCESS on success, appropriate error code otherwise.
 
1185
 *
 
1186
 * Side effects:
 
1187
 *      Memory will be allocated, and pages may be pinned.
 
1188
 *
 
1189
 *-----------------------------------------------------------------------------
 
1190
 */
 
1191
 
 
1192
static int
 
1193
VMCIQPBrokerAttach(QPBrokerEntry *entry,          // IN
 
1194
                   VMCIId peer,                   // IN
 
1195
                   uint32 flags,                  // IN
 
1196
                   VMCIPrivilegeFlags privFlags,  // IN
 
1197
                   uint64 produceSize,            // IN
 
1198
                   uint64 consumeSize,            // IN
 
1199
                   QueuePairPageStore *pageStore, // IN/OUT
 
1200
                   VMCIContext *context,          // IN: Caller
 
1201
                   VMCIEventReleaseCB wakeupCB,   // IN
 
1202
                   void *clientData,              // IN
 
1203
                   QPBrokerEntry **ent)           // OUT
 
1204
{
 
1205
   const VMCIId contextId = VMCIContext_GetId(context);
 
1206
   Bool isLocal = flags & VMCI_QPFLAG_LOCAL;
 
1207
   int result;
 
1208
 
 
1209
   if (entry->state != VMCIQPB_CREATED_NO_MEM &&
 
1210
       entry->state != VMCIQPB_CREATED_MEM) {
 
1211
      return VMCI_ERROR_UNAVAILABLE;
 
1212
   }
 
1213
 
 
1214
   if (isLocal) {
 
1215
      if (!(entry->qp.flags & VMCI_QPFLAG_LOCAL) ||
 
1216
          contextId != entry->createId) {
 
1217
         return VMCI_ERROR_INVALID_ARGS;
 
1218
      }
 
1219
   } else if (contextId == entry->createId || contextId == entry->attachId) {
 
1220
      return VMCI_ERROR_ALREADY_EXISTS;
 
1221
   }
 
1222
 
 
1223
   ASSERT(entry->qp.refCount < 2);
 
1224
   ASSERT(entry->attachId == VMCI_INVALID_ID);
 
1225
 
 
1226
   if (VMCI_CONTEXT_IS_VM(contextId) && VMCI_CONTEXT_IS_VM(entry->createId)) {
 
1227
      return VMCI_ERROR_DST_UNREACHABLE;
 
1228
   }
 
1229
 
 
1230
   /*
 
1231
    * If we are attaching from a restricted context then the queuepair
 
1232
    * must have been created by a trusted endpoint.
 
1233
    */
 
1234
 
 
1235
   if (context->privFlags & VMCI_PRIVILEGE_FLAG_RESTRICTED) {
 
1236
      if (!entry->createdByTrusted) {
 
1237
         return VMCI_ERROR_NO_ACCESS;
 
1238
      }
 
1239
   }
 
1240
 
 
1241
   /*
 
1242
    * If we are attaching to a queuepair that was created by a restricted
 
1243
    * context then we must be trusted.
 
1244
    */
 
1245
 
 
1246
   if (entry->requireTrustedAttach) {
 
1247
      if (!(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED)) {
 
1248
         return VMCI_ERROR_NO_ACCESS;
 
1249
      }
 
1250
   }
 
1251
 
 
1252
   /*
 
1253
    * If the creator specifies VMCI_INVALID_ID in "peer" field, access
 
1254
    * control check is not performed.
 
1255
    */
 
1256
 
 
1257
   if (entry->qp.peer != VMCI_INVALID_ID && entry->qp.peer != contextId) {
 
1258
      return VMCI_ERROR_NO_ACCESS;
 
1259
   }
 
1260
 
 
1261
   if (entry->createId == VMCI_HOST_CONTEXT_ID) {
 
1262
      /*
 
1263
       * Do not attach if the caller doesn't support Host Queue Pairs
 
1264
       * and a host created this queue pair.
 
1265
       */
 
1266
 
 
1267
      if (!VMCIContext_SupportsHostQP(context)) {
 
1268
         return VMCI_ERROR_INVALID_RESOURCE;
 
1269
      }
 
1270
   } else if (contextId == VMCI_HOST_CONTEXT_ID) {
 
1271
      VMCIContext *createContext;
 
1272
      Bool supportsHostQP;
 
1273
 
 
1274
      /*
 
1275
       * Do not attach a host to a user created queue pair if that
 
1276
       * user doesn't support host queue pair end points.
 
1277
       */
 
1278
 
 
1279
      createContext = VMCIContext_Get(entry->createId);
 
1280
      supportsHostQP = VMCIContext_SupportsHostQP(createContext);
 
1281
      VMCIContext_Release(createContext);
 
1282
 
 
1283
      if (!supportsHostQP) {
 
1284
         return VMCI_ERROR_INVALID_RESOURCE;
 
1285
      }
 
1286
   }
 
1287
 
 
1288
   if ((entry->qp.flags & ~VMCI_QP_ASYMM) != (flags & ~VMCI_QP_ASYMM_PEER)) {
 
1289
      return VMCI_ERROR_QUEUEPAIR_MISMATCH;
 
1290
   }
 
1291
 
 
1292
   if (contextId != VMCI_HOST_CONTEXT_ID) {
 
1293
      /*
 
1294
       * The queue pair broker entry stores values from the guest
 
1295
       * point of view, so an attaching guest should match the values
 
1296
       * stored in the entry.
 
1297
       */
 
1298
 
 
1299
      if (entry->qp.produceSize != produceSize ||
 
1300
          entry->qp.consumeSize != consumeSize) {
 
1301
         return VMCI_ERROR_QUEUEPAIR_MISMATCH;
 
1302
      }
 
1303
   } else if (entry->qp.produceSize != consumeSize ||
 
1304
              entry->qp.consumeSize != produceSize) {
 
1305
      return VMCI_ERROR_QUEUEPAIR_MISMATCH;
 
1306
   }
 
1307
 
 
1308
   if (contextId != VMCI_HOST_CONTEXT_ID) {
 
1309
      /*
 
1310
       * If a guest attached to a queue pair, it will supply the backing memory.
 
1311
       * If this is a pre NOVMVM vmx, the backing memory will be supplied by
 
1312
       * calling VMCIQPBroker_SetPageStore() following the return of the
 
1313
       * VMCIQPBroker_Alloc() call. If it is a vmx of version NOVMVM or later,
 
1314
       * the page store must be supplied as part of the VMCIQPBroker_Alloc call.
 
1315
       * Under all circumstances must the initially created queue pair not have
 
1316
       * any memory associated with it already.
 
1317
       */
 
1318
 
 
1319
      if (entry->state != VMCIQPB_CREATED_NO_MEM) {
 
1320
         return VMCI_ERROR_INVALID_ARGS;
 
1321
      }
 
1322
 
 
1323
      if (pageStore != NULL) {
 
1324
         /*
 
1325
          * Patch up host state to point to guest supplied memory. The VMX
 
1326
          * already initialized the queue pair headers, so no need for the
 
1327
          * kernel side to do that.
 
1328
          */
 
1329
 
 
1330
         result = VMCIHost_RegisterUserMemory(pageStore,
 
1331
                                              entry->produceQ,
 
1332
                                              entry->consumeQ);
 
1333
         if (result < VMCI_SUCCESS) {
 
1334
            return result;
 
1335
         }
 
1336
         VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
 
1337
         if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
 
1338
            result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ,
 
1339
                                        entry->qp.flags);
 
1340
            if (result < VMCI_SUCCESS) {
 
1341
               VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ);
 
1342
               return result;
 
1343
            }
 
1344
         }
 
1345
         entry->state = VMCIQPB_ATTACHED_MEM;
 
1346
      } else {
 
1347
         entry->state = VMCIQPB_ATTACHED_NO_MEM;
 
1348
      }
 
1349
   } else if (entry->state == VMCIQPB_CREATED_NO_MEM) {
 
1350
      /*
 
1351
       * The host side is attempting to attach to a queue pair that doesn't have
 
1352
       * any memory associated with it. This must be a pre NOVMVM vmx that hasn't
 
1353
       * set the page store information yet, or a quiesced VM.
 
1354
       */
 
1355
 
 
1356
      return VMCI_ERROR_UNAVAILABLE;
 
1357
   } else {
 
1358
      /*
 
1359
       * For non-blocking queue pairs, we cannot rely on enqueue/dequeue to map
 
1360
       * in the pages on the host-side, since it may block, so we make an attempt
 
1361
       * here.
 
1362
       */
 
1363
 
 
1364
      if (flags & VMCI_QPFLAG_NONBLOCK) {
 
1365
         result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, flags);
 
1366
         if (result < VMCI_SUCCESS) {
 
1367
            return result;
 
1368
         }
 
1369
         entry->qp.flags |= flags & (VMCI_QPFLAG_NONBLOCK | VMCI_QPFLAG_PINNED);
 
1370
      }
 
1371
 
 
1372
      /*
 
1373
       * The host side has successfully attached to a queue pair.
 
1374
       */
 
1375
 
 
1376
      entry->state = VMCIQPB_ATTACHED_MEM;
 
1377
   }
 
1378
 
 
1379
   if (entry->state == VMCIQPB_ATTACHED_MEM) {
 
1380
      result = QueuePairNotifyPeer(TRUE, entry->qp.handle, contextId,
 
1381
                                   entry->createId);
 
1382
      if (result < VMCI_SUCCESS) {
 
1383
         VMCI_WARNING((LGPFX"Failed to notify peer (ID=0x%x) of attach to queue "
 
1384
                       "pair (handle=0x%x:0x%x).\n", entry->createId,
 
1385
                       entry->qp.handle.context, entry->qp.handle.resource));
 
1386
      }
 
1387
   }
 
1388
 
 
1389
   entry->attachId = contextId;
 
1390
   entry->qp.refCount++;
 
1391
   if (wakeupCB) {
 
1392
      ASSERT(!entry->wakeupCB);
 
1393
      entry->wakeupCB = wakeupCB;
 
1394
      entry->clientData = clientData;
 
1395
   }
 
1396
 
 
1397
   /*
 
1398
    * When attaching to local queue pairs, the context already has
 
1399
    * an entry tracking the queue pair, so don't add another one.
 
1400
    */
 
1401
 
 
1402
   if (!isLocal) {
 
1403
      VMCIContext_QueuePairCreate(context, entry->qp.handle);
 
1404
   } else {
 
1405
      ASSERT(VMCIContext_QueuePairExists(context, entry->qp.handle));
 
1406
   }
 
1407
   if (ent != NULL) {
 
1408
      *ent = entry;
 
1409
   }
 
1410
 
 
1411
   return VMCI_SUCCESS;
 
1412
}
 
1413
 
 
1414
 
 
1415
/*
 
1416
 *-----------------------------------------------------------------------------
 
1417
 *
 
1418
 * VMCIQPBroker_SetPageStore --
 
1419
 *
 
1420
 *      VMX'en with versions lower than VMCI_VERSION_NOVMVM use a separate
 
1421
 *      step to add the UVAs of the VMX mapping of the queue pair. This function
 
1422
 *      provides backwards compatibility with such VMX'en, and takes care of
 
1423
 *      registering the page store for a queue pair previously allocated by the
 
1424
 *      VMX during create or attach. This function will move the queue pair state
 
1425
 *      to either from VMCIQBP_CREATED_NO_MEM to VMCIQBP_CREATED_MEM or
 
1426
 *      VMCIQBP_ATTACHED_NO_MEM to VMCIQBP_ATTACHED_MEM. If moving to the
 
1427
 *      attached state with memory, the queue pair is ready to be used by the
 
1428
 *      host peer, and an attached event will be generated.
 
1429
 *
 
1430
 *      Assumes that the queue pair broker lock is held.
 
1431
 *
 
1432
 *      This function is only used by the hosted platform, since there is no
 
1433
 *      issue with backwards compatibility for vmkernel.
 
1434
 *
 
1435
 * Results:
 
1436
 *      VMCI_SUCCESS on success, appropriate error code otherwise.
 
1437
 *
 
1438
 * Side effects:
 
1439
 *      Pages may get pinned.
 
1440
 *
 
1441
 *-----------------------------------------------------------------------------
 
1442
 */
 
1443
 
 
1444
int
 
1445
VMCIQPBroker_SetPageStore(VMCIHandle handle,      // IN
 
1446
                          VA64 produceUVA,        // IN
 
1447
                          VA64 consumeUVA,        // IN
 
1448
                          VMCIContext *context)   // IN: Caller
 
1449
{
 
1450
   QPBrokerEntry *entry;
 
1451
   int result;
 
1452
   const VMCIId contextId = VMCIContext_GetId(context);
 
1453
 
 
1454
   if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
 
1455
      return VMCI_ERROR_INVALID_ARGS;
 
1456
   }
 
1457
 
 
1458
   /*
 
1459
    * We only support guest to host queue pairs, so the VMX must
 
1460
    * supply UVAs for the mapped page files.
 
1461
    */
 
1462
 
 
1463
   if (produceUVA == 0 || consumeUVA == 0) {
 
1464
      return VMCI_ERROR_INVALID_ARGS;
 
1465
   }
 
1466
 
 
1467
   VMCIQPBrokerLock();
 
1468
 
 
1469
   if (!VMCIContext_QueuePairExists(context, handle)) {
 
1470
      VMCI_WARNING((LGPFX"Context (ID=0x%x) not attached to queue pair "
 
1471
                    "(handle=0x%x:0x%x).\n", contextId, handle.context,
 
1472
                    handle.resource));
 
1473
      result = VMCI_ERROR_NOT_FOUND;
 
1474
      goto out;
 
1475
   }
 
1476
 
 
1477
   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
 
1478
   if (!entry) {
 
1479
      result = VMCI_ERROR_NOT_FOUND;
 
1480
      goto out;
 
1481
   }
 
1482
 
 
1483
   /*
 
1484
    * If I'm the owner then I can set the page store.
 
1485
    *
 
1486
    * Or, if a host created the QueuePair and I'm the attached peer
 
1487
    * then I can set the page store.
 
1488
    */
 
1489
 
 
1490
   if (entry->createId != contextId &&
 
1491
       (entry->createId != VMCI_HOST_CONTEXT_ID ||
 
1492
        entry->attachId != contextId)) {
 
1493
      result = VMCI_ERROR_QUEUEPAIR_NOTOWNER;
 
1494
      goto out;
 
1495
   }
 
1496
 
 
1497
   if (entry->state != VMCIQPB_CREATED_NO_MEM &&
 
1498
       entry->state != VMCIQPB_ATTACHED_NO_MEM) {
 
1499
      result = VMCI_ERROR_UNAVAILABLE;
 
1500
      goto out;
 
1501
   }
 
1502
 
 
1503
   result = VMCIHost_GetUserMemory(produceUVA, consumeUVA,
 
1504
                                   entry->produceQ, entry->consumeQ);
 
1505
   if (result < VMCI_SUCCESS) {
 
1506
      goto out;
 
1507
   }
 
1508
   VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
 
1509
   result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, FALSE);
 
1510
   if (result < VMCI_SUCCESS) {
 
1511
     VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ);
 
1512
     goto out;
 
1513
   }
 
1514
 
 
1515
   if (entry->state == VMCIQPB_CREATED_NO_MEM) {
 
1516
      entry->state = VMCIQPB_CREATED_MEM;
 
1517
   } else {
 
1518
      ASSERT(entry->state == VMCIQPB_ATTACHED_NO_MEM);
 
1519
      entry->state = VMCIQPB_ATTACHED_MEM;
 
1520
   }
 
1521
   entry->vmciPageFiles = TRUE;
 
1522
 
 
1523
   if (entry->state == VMCIQPB_ATTACHED_MEM) {
 
1524
      result = QueuePairNotifyPeer(TRUE, handle, contextId, entry->createId);
 
1525
      if (result < VMCI_SUCCESS) {
 
1526
         VMCI_WARNING((LGPFX"Failed to notify peer (ID=0x%x) of attach to queue "
 
1527
                       "pair (handle=0x%x:0x%x).\n", entry->createId,
 
1528
                       entry->qp.handle.context, entry->qp.handle.resource));
 
1529
      }
 
1530
   }
 
1531
 
 
1532
   result = VMCI_SUCCESS;
 
1533
out:
 
1534
   VMCIQPBrokerUnlock();
 
1535
   return result;
 
1536
}
 
1537
 
 
1538
 
 
1539
/*
 
1540
 *-----------------------------------------------------------------------------
 
1541
 *
 
1542
 * VMCIQPBroker_Detach --
 
1543
 *
 
1544
 *      The main entry point for detaching from a queue pair registered with the
 
1545
 *      queue pair broker. If more than one endpoint is attached to the queue
 
1546
 *      pair, the first endpoint will mainly decrement a reference count and
 
1547
 *      generate a notification to its peer. The last endpoint will clean up
 
1548
 *      the queue pair state registered with the broker.
 
1549
 *
 
1550
 *      When a guest endpoint detaches, it will unmap and unregister the guest
 
1551
 *      memory backing the queue pair. If the host is still attached, it will
 
1552
 *      no longer be able to access the queue pair content.
 
1553
 *
 
1554
 *      If the queue pair is already in a state where there is no memory
 
1555
 *      registered for the queue pair (any *_NO_MEM state), it will transition to
 
1556
 *      the VMCIQPB_SHUTDOWN_NO_MEM state. This will also happen, if a guest 
 
1557
 *      endpoint is the first of two endpoints to detach. If the host endpoint is
 
1558
 *      the first out of two to detach, the queue pair will move to the
 
1559
 *      VMCIQPB_SHUTDOWN_MEM state.
 
1560
 *
 
1561
 * Results:
 
1562
 *      VMCI_SUCCESS on success, appropriate error code otherwise.
 
1563
 *
 
1564
 * Side effects:
 
1565
 *      Memory may be freed, and pages may be unpinned.
 
1566
 *
 
1567
 *-----------------------------------------------------------------------------
 
1568
 */
 
1569
 
 
1570
int
 
1571
VMCIQPBroker_Detach(VMCIHandle  handle,   // IN
 
1572
                    VMCIContext *context) // IN
 
1573
{
 
1574
   QPBrokerEntry *entry;
 
1575
   const VMCIId contextId = VMCIContext_GetId(context);
 
1576
   VMCIId peerId;
 
1577
   Bool isLocal = FALSE;
 
1578
   int result;
 
1579
 
 
1580
   if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
 
1581
      return VMCI_ERROR_INVALID_ARGS;
 
1582
   }
 
1583
 
 
1584
   VMCIQPBrokerLock();
 
1585
 
 
1586
   if (!VMCIContext_QueuePairExists(context, handle)) {
 
1587
      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
 
1588
                         "(handle=0x%x:0x%x).\n",
 
1589
                         contextId, handle.context, handle.resource));
 
1590
      result = VMCI_ERROR_NOT_FOUND;
 
1591
      goto out;
 
1592
   }
 
1593
 
 
1594
   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
 
1595
   if (!entry) {
 
1596
      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair "
 
1597
                         "(handle=0x%x:0x%x) that isn't present in broker.\n",
 
1598
                         contextId, handle.context, handle.resource));
 
1599
      result = VMCI_ERROR_NOT_FOUND;
 
1600
      goto out;
 
1601
   }
 
1602
 
 
1603
   if (contextId != entry->createId && contextId != entry->attachId) {
 
1604
      result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
 
1605
      goto out;
 
1606
   }
 
1607
 
 
1608
   if (contextId == entry->createId) {
 
1609
      peerId = entry->attachId;
 
1610
      entry->createId = VMCI_INVALID_ID;
 
1611
   } else {
 
1612
      peerId = entry->createId;
 
1613
      entry->attachId = VMCI_INVALID_ID;
 
1614
   }
 
1615
   entry->qp.refCount--;
 
1616
 
 
1617
   isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
 
1618
 
 
1619
   if (contextId != VMCI_HOST_CONTEXT_ID) {
 
1620
      int result;
 
1621
      Bool headersMapped;
 
1622
 
 
1623
      ASSERT(!isLocal);
 
1624
 
 
1625
      /*
 
1626
       * Pre NOVMVM vmx'en may detach from a queue pair before setting the page
 
1627
       * store, and in that case there is no user memory to detach from. Also,
 
1628
       * more recent VMX'en may detach from a queue pair in the quiesced state.
 
1629
       */
 
1630
 
 
1631
      VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
 
1632
      headersMapped = entry->produceQ->qHeader || entry->consumeQ->qHeader;
 
1633
      if (QPBROKERSTATE_HAS_MEM(entry)) {
 
1634
         result = VMCIHost_UnmapQueues(INVALID_VMCI_GUEST_MEM_ID,
 
1635
                                       entry->produceQ,
 
1636
                                       entry->consumeQ);
 
1637
         if (result < VMCI_SUCCESS) {
 
1638
            VMCI_WARNING((LGPFX"Failed to unmap queue headers for queue pair "
 
1639
                          "(handle=0x%x:0x%x,result=%d).\n", handle.context,
 
1640
                          handle.resource, result));
 
1641
         }
 
1642
         VMCIHost_MarkQueuesUnavailable(entry->produceQ, entry->consumeQ);
 
1643
         if (entry->vmciPageFiles) {
 
1644
            VMCIHost_ReleaseUserMemory(entry->produceQ, entry->consumeQ);
 
1645
         } else {
 
1646
            VMCIHost_UnregisterUserMemory(entry->produceQ, entry->consumeQ);
 
1647
         }
 
1648
      }
 
1649
      if (!headersMapped) {
 
1650
         QueuePairResetSavedHeaders(entry);
 
1651
      }
 
1652
      VMCI_ReleaseQueueMutex(entry->produceQ);
 
1653
      if (!headersMapped && entry->wakeupCB) {
 
1654
         entry->wakeupCB(entry->clientData);
 
1655
      }
 
1656
   } else {
 
1657
      if (entry->wakeupCB) {
 
1658
         entry->wakeupCB = NULL;
 
1659
         entry->clientData = NULL;
 
1660
      }
 
1661
   }
 
1662
 
 
1663
   if (entry->qp.refCount == 0) {
 
1664
      QueuePairList_RemoveEntry(&qpBrokerList, &entry->qp);
 
1665
 
 
1666
      if (isLocal) {
 
1667
         VMCI_FreeKernelMem(entry->localMem, QPE_NUM_PAGES(entry->qp) * PAGE_SIZE);
 
1668
      }
 
1669
      VMCI_CleanupQueueMutex(entry->produceQ, entry->consumeQ);
 
1670
      VMCIHost_FreeQueue(entry->produceQ, entry->qp.produceSize);
 
1671
      VMCIHost_FreeQueue(entry->consumeQ, entry->qp.consumeSize);
 
1672
      VMCI_FreeKernelMem(entry, sizeof *entry);
 
1673
 
 
1674
      VMCIContext_QueuePairDestroy(context, handle);
 
1675
   } else {
 
1676
      ASSERT(peerId != VMCI_INVALID_ID);
 
1677
      QueuePairNotifyPeer(FALSE, handle, contextId, peerId);
 
1678
      if (contextId == VMCI_HOST_CONTEXT_ID && QPBROKERSTATE_HAS_MEM(entry)) {
 
1679
         entry->state = VMCIQPB_SHUTDOWN_MEM;
 
1680
      } else {
 
1681
         entry->state = VMCIQPB_SHUTDOWN_NO_MEM;
 
1682
      }
 
1683
      if (!isLocal) {
 
1684
         VMCIContext_QueuePairDestroy(context, handle);
 
1685
      }
 
1686
   }
 
1687
   result = VMCI_SUCCESS;
 
1688
out:
 
1689
   VMCIQPBrokerUnlock();
 
1690
   return result;
 
1691
}
 
1692
 
 
1693
 
 
1694
/*
 
1695
 *-----------------------------------------------------------------------------
 
1696
 *
 
1697
 * VMCIQPBroker_Map --
 
1698
 *
 
1699
 *      Establishes the necessary mappings for a queue pair given a
 
1700
 *      reference to the queue pair guest memory. This is usually
 
1701
 *      called when a guest is unquiesced and the VMX is allowed to
 
1702
 *      map guest memory once again.
 
1703
 *
 
1704
 * Results:
 
1705
 *      VMCI_SUCCESS on success, appropriate error code otherwise.
 
1706
 *
 
1707
 * Side effects:
 
1708
 *      Memory may be allocated, and pages may be pinned.
 
1709
 *
 
1710
 *-----------------------------------------------------------------------------
 
1711
 */
 
1712
 
 
1713
int
 
1714
VMCIQPBroker_Map(VMCIHandle  handle,      // IN
 
1715
                 VMCIContext *context,    // IN
 
1716
                 VMCIQPGuestMem guestMem) // IN
 
1717
{
 
1718
   QPBrokerEntry *entry;
 
1719
   const VMCIId contextId = VMCIContext_GetId(context);
 
1720
   Bool isLocal = FALSE;
 
1721
   int result;
 
1722
 
 
1723
   if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
 
1724
      return VMCI_ERROR_INVALID_ARGS;
 
1725
   }
 
1726
 
 
1727
   VMCIQPBrokerLock();
 
1728
 
 
1729
   if (!VMCIContext_QueuePairExists(context, handle)) {
 
1730
      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
 
1731
                         "(handle=0x%x:0x%x).\n",
 
1732
                         contextId, handle.context, handle.resource));
 
1733
      result = VMCI_ERROR_NOT_FOUND;
 
1734
      goto out;
 
1735
   }
 
1736
 
 
1737
   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
 
1738
   if (!entry) {
 
1739
      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair "
 
1740
                         "(handle=0x%x:0x%x) that isn't present in broker.\n",
 
1741
                         contextId, handle.context, handle.resource));
 
1742
      result = VMCI_ERROR_NOT_FOUND;
 
1743
      goto out;
 
1744
   }
 
1745
 
 
1746
   if (contextId != entry->createId && contextId != entry->attachId) {
 
1747
      result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
 
1748
      goto out;
 
1749
   }
 
1750
 
 
1751
   isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
 
1752
 
 
1753
   if (vmkernel) {
 
1754
      /*
 
1755
       * On vmkernel, the readiness of the queue pair can be signalled
 
1756
       * immediately since the guest memory is already registered.
 
1757
       */
 
1758
 
 
1759
      VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
 
1760
      VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
 
1761
      if (entry->qp.flags & VMCI_QPFLAG_NONBLOCK) {
 
1762
         result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ,
 
1763
                                     entry->qp.flags);
 
1764
      } else {
 
1765
         result = VMCI_SUCCESS;
 
1766
      }
 
1767
      if (result == VMCI_SUCCESS) {
 
1768
         QueuePairResetSavedHeaders(entry);
 
1769
      }
 
1770
      VMCI_ReleaseQueueMutex(entry->produceQ);
 
1771
      if (result == VMCI_SUCCESS) {
 
1772
         if (entry->wakeupCB) {
 
1773
            entry->wakeupCB(entry->clientData);
 
1774
         }
 
1775
      }
 
1776
   } else  if (contextId != VMCI_HOST_CONTEXT_ID) {
 
1777
      QueuePairPageStore pageStore;
 
1778
 
 
1779
      ASSERT(entry->state == VMCIQPB_CREATED_NO_MEM ||
 
1780
             entry->state == VMCIQPB_SHUTDOWN_NO_MEM ||
 
1781
             entry->state == VMCIQPB_ATTACHED_NO_MEM);
 
1782
      ASSERT(!isLocal);
 
1783
 
 
1784
      pageStore.pages = guestMem;
 
1785
      pageStore.len = QPE_NUM_PAGES(entry->qp);
 
1786
 
 
1787
      VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
 
1788
      QueuePairResetSavedHeaders(entry);
 
1789
      result = VMCIHost_RegisterUserMemory(&pageStore, entry->produceQ, entry->consumeQ);
 
1790
      VMCIHost_MarkQueuesAvailable(entry->produceQ, entry->consumeQ);
 
1791
      VMCI_ReleaseQueueMutex(entry->produceQ);
 
1792
      if (result == VMCI_SUCCESS) {
 
1793
         /*
 
1794
          * Move state from *_NO_MEM to *_MEM.
 
1795
          */
 
1796
 
 
1797
         entry->state++;
 
1798
 
 
1799
         ASSERT(entry->state == VMCIQPB_CREATED_MEM ||
 
1800
                entry->state == VMCIQPB_SHUTDOWN_MEM ||
 
1801
                entry->state == VMCIQPB_ATTACHED_MEM);
 
1802
 
 
1803
         if (entry->wakeupCB) {
 
1804
            entry->wakeupCB(entry->clientData);
 
1805
         }
 
1806
      }
 
1807
   } else {
 
1808
      result = VMCI_SUCCESS;
 
1809
   }
 
1810
 
 
1811
out:
 
1812
   VMCIQPBrokerUnlock();
 
1813
   return result;
 
1814
}
 
1815
 
 
1816
 
 
1817
/*
 
1818
 *-----------------------------------------------------------------------------
 
1819
 *
 
1820
 * QueuePairSaveHeaders --
 
1821
 *
 
1822
 *      Saves a snapshot of the queue headers for the given QP broker
 
1823
 *      entry. Should be used when guest memory is unmapped.
 
1824
 *
 
1825
 * Results:
 
1826
 *      VMCI_SUCCESS on success, appropriate error code if guest memory
 
1827
 *      can't be accessed..
 
1828
 *
 
1829
 * Side effects:
 
1830
 *      None.
 
1831
 *
 
1832
 *-----------------------------------------------------------------------------
 
1833
 */
 
1834
 
 
1835
static int
 
1836
QueuePairSaveHeaders(QPBrokerEntry *entry) // IN
 
1837
{
 
1838
   int result;
 
1839
 
 
1840
   if (entry->produceQ->savedHeader != NULL &&
 
1841
       entry->consumeQ->savedHeader != NULL) {
 
1842
      /*
 
1843
       *  If the headers have already been saved, we don't need to do
 
1844
       *  it again, and we don't want to map in the headers
 
1845
       *  unnecessarily.
 
1846
       */
 
1847
 
 
1848
      return VMCI_SUCCESS;
 
1849
   }
 
1850
   if (NULL == entry->produceQ->qHeader || NULL == entry->consumeQ->qHeader) {
 
1851
      result = VMCIHost_MapQueues(entry->produceQ, entry->consumeQ, FALSE);
 
1852
      if (result < VMCI_SUCCESS) {
 
1853
         return result;
 
1854
      }
 
1855
   }
 
1856
   memcpy(&entry->savedProduceQ, entry->produceQ->qHeader,
 
1857
          sizeof entry->savedProduceQ);
 
1858
   entry->produceQ->savedHeader = &entry->savedProduceQ;
 
1859
   memcpy(&entry->savedConsumeQ, entry->consumeQ->qHeader,
 
1860
          sizeof entry->savedConsumeQ);
 
1861
   entry->consumeQ->savedHeader = &entry->savedConsumeQ;
 
1862
 
 
1863
   return VMCI_SUCCESS;
 
1864
}
 
1865
 
 
1866
 
 
1867
/*
 
1868
 *-----------------------------------------------------------------------------
 
1869
 *
 
1870
 * QueuePairResetSavedHeaders --
 
1871
 *
 
1872
 *      Resets saved queue headers for the given QP broker
 
1873
 *      entry. Should be used when guest memory becomes available
 
1874
 *      again, or the guest detaches.
 
1875
 *
 
1876
 * Results:
 
1877
 *      None.
 
1878
 *
 
1879
 * Side effects:
 
1880
 *      None.
 
1881
 *
 
1882
 *-----------------------------------------------------------------------------
 
1883
 */
 
1884
 
 
1885
static void
 
1886
QueuePairResetSavedHeaders(QPBrokerEntry *entry) // IN
 
1887
{
 
1888
   if (vmkernel) {
 
1889
      VMCI_LockQueueHeader(entry->produceQ);
 
1890
   }
 
1891
   entry->produceQ->savedHeader = NULL;
 
1892
   entry->consumeQ->savedHeader = NULL;
 
1893
   if (vmkernel) {
 
1894
      VMCI_UnlockQueueHeader(entry->produceQ);
 
1895
   }
 
1896
}
 
1897
 
 
1898
 
 
1899
/*
 
1900
 *-----------------------------------------------------------------------------
 
1901
 *
 
1902
 * VMCIQPBroker_Unmap --
 
1903
 *
 
1904
 *      Removes all references to the guest memory of a given queue pair, and
 
1905
 *      will move the queue pair from state *_MEM to *_NO_MEM. It is usually
 
1906
 *      called when a VM is being quiesced where access to guest memory should
 
1907
 *      avoided.
 
1908
 *
 
1909
 * Results:
 
1910
 *      VMCI_SUCCESS on success, appropriate error code otherwise.
 
1911
 *
 
1912
 * Side effects:
 
1913
 *      Memory may be freed, and pages may be unpinned.
 
1914
 *
 
1915
 *-----------------------------------------------------------------------------
 
1916
 */
 
1917
 
 
1918
int
 
1919
VMCIQPBroker_Unmap(VMCIHandle  handle,   // IN
 
1920
                   VMCIContext *context, // IN
 
1921
                   VMCIGuestMemID gid)   // IN
 
1922
{
 
1923
   QPBrokerEntry *entry;
 
1924
   const VMCIId contextId = VMCIContext_GetId(context);
 
1925
   Bool isLocal = FALSE;
 
1926
   int result;
 
1927
 
 
1928
   if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
 
1929
      return VMCI_ERROR_INVALID_ARGS;
 
1930
   }
 
1931
 
 
1932
   VMCIQPBrokerLock();
 
1933
   if (!VMCIContext_QueuePairExists(context, handle)) {
 
1934
      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) not attached to queue pair "
 
1935
                         "(handle=0x%x:0x%x).\n",
 
1936
                         contextId, handle.context, handle.resource));
 
1937
      result = VMCI_ERROR_NOT_FOUND;
 
1938
      goto out;
 
1939
   }
 
1940
 
 
1941
   entry = (QPBrokerEntry *)QueuePairList_FindEntry(&qpBrokerList, handle);
 
1942
   if (!entry) {
 
1943
      VMCI_DEBUG_LOG(4, (LGPFX"Context (ID=0x%x) reports being attached to queue pair "
 
1944
                         "(handle=0x%x:0x%x) that isn't present in broker.\n",
 
1945
                         contextId, handle.context, handle.resource));
 
1946
      result = VMCI_ERROR_NOT_FOUND;
 
1947
      goto out;
 
1948
   }
 
1949
 
 
1950
   if (contextId != entry->createId && contextId != entry->attachId) {
 
1951
      result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
 
1952
      goto out;
 
1953
   }
 
1954
 
 
1955
   isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
 
1956
 
 
1957
   if (contextId != VMCI_HOST_CONTEXT_ID) {
 
1958
      ASSERT(entry->state != VMCIQPB_CREATED_NO_MEM &&
 
1959
             entry->state != VMCIQPB_SHUTDOWN_NO_MEM &&
 
1960
             entry->state != VMCIQPB_ATTACHED_NO_MEM);
 
1961
      ASSERT(!isLocal);
 
1962
 
 
1963
      VMCI_AcquireQueueMutex(entry->produceQ, TRUE);
 
1964
      result = QueuePairSaveHeaders(entry);
 
1965
      if (result < VMCI_SUCCESS) {
 
1966
         VMCI_WARNING((LGPFX"Failed to save queue headers for queue pair "
 
1967
                       "(handle=0x%x:0x%x,result=%d).\n", handle.context,
 
1968
                       handle.resource, result));
 
1969
      }
 
1970
      VMCIHost_UnmapQueues(gid, entry->produceQ, entry->consumeQ);
 
1971
      VMCIHost_MarkQueuesUnavailable(entry->produceQ, entry->consumeQ);
 
1972
      if (!vmkernel) {
 
1973
         /*
 
1974
          * On hosted, when we unmap queue pairs, the VMX will also
 
1975
          * unmap the guest memory, so we invalidate the previously
 
1976
          * registered memory. If the queue pair is mapped again at a
 
1977
          * later point in time, we will need to reregister the user
 
1978
          * memory with a possibly new user VA.
 
1979
          */
 
1980
 
 
1981
         VMCIHost_UnregisterUserMemory(entry->produceQ, entry->consumeQ);
 
1982
 
 
1983
         /*
 
1984
          * Move state from *_MEM to *_NO_MEM.
 
1985
          */
 
1986
 
 
1987
         entry->state--;
 
1988
      }
 
1989
 
 
1990
      VMCI_ReleaseQueueMutex(entry->produceQ);
 
1991
   }
 
1992
 
 
1993
   result = VMCI_SUCCESS;
 
1994
out:
 
1995
   VMCIQPBrokerUnlock();
 
1996
   return result;
 
1997
}
 
1998
 
 
1999
#if !defined(VMKERNEL)
 
2000
 
 
2001
/*
 
2002
 *-----------------------------------------------------------------------------
 
2003
 *
1656
2004
 * VMCIQPGuestEndpoints_Init --
1657
2005
 *
1658
2006
 *      Initalizes data structure state keeping track of queue pair
1659
2007
 *      guest endpoints.
1660
2008
 *
1661
2009
 * Results:
1662
 
 *      None.
 
2010
 *      VMCI_SUCCESS on success and appropriate failure code otherwise.
1663
2011
 *
1664
2012
 * Side effects:
1665
2013
 *      None.
1690
2038
    */
1691
2039
 
1692
2040
   err = VMCI_InitLock(&hibernateFailedListLock, "VMCIQPHibernateFailed",
1693
 
                       VMCI_LOCK_RANK_MIDDLE_BH);
 
2041
                       VMCI_LOCK_RANK_QPHIBERNATE);
1694
2042
   if (err < VMCI_SUCCESS) {
1695
2043
      VMCIHandleArray_Destroy(hibernateFailedList);
1696
2044
      hibernateFailedList = NULL;
1725
2073
{
1726
2074
   QPGuestEndpoint *entry;
1727
2075
 
1728
 
   VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
 
2076
   VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
1729
2077
 
1730
2078
   while ((entry = (QPGuestEndpoint *)QueuePairList_GetHead(&qpGuestEndpoints))) {
1731
2079
      /*
1743
2091
   }
1744
2092
 
1745
2093
   Atomic_Write(&qpGuestEndpoints.hibernate, 0);
1746
 
   VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
2094
   VMCIMutex_Release(&qpGuestEndpoints.mutex);
1747
2095
   QueuePairList_Destroy(&qpGuestEndpoints);
1748
2096
   VMCI_CleanupLock(&hibernateFailedListLock);
1749
2097
   VMCIHandleArray_Destroy(hibernateFailedList);
1770
2118
void
1771
2119
VMCIQPGuestEndpoints_Sync(void)
1772
2120
{
1773
 
   VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
1774
 
   VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
2121
   VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
 
2122
   VMCIMutex_Release(&qpGuestEndpoints.mutex);
1775
2123
}
1776
2124
 
1777
2125
 
1783
2131
 *      Allocates and initializes a QPGuestEndpoint structure.
1784
2132
 *      Allocates a QueuePair rid (and handle) iff the given entry has
1785
2133
 *      an invalid handle.  0 through VMCI_RESERVED_RESOURCE_ID_MAX
1786
 
 *      are reserved handles.  Assumes that the QP list lock is held
 
2134
 *      are reserved handles.  Assumes that the QP list mutex is held
1787
2135
 *      by the caller.
1788
2136
 *
1789
2137
 * Results:
1886
2234
   ASSERT(entry->qp.refCount == 0);
1887
2235
 
1888
2236
   VMCI_FreePPNSet(&entry->ppnSet);
 
2237
   VMCI_CleanupQueueMutex(entry->produceQ, entry->consumeQ);
1889
2238
   VMCI_FreeQueue(entry->produceQ, entry->qp.produceSize);
1890
2239
   VMCI_FreeQueue(entry->consumeQ, entry->qp.consumeSize);
1891
2240
   VMCI_FreeKernelMem(entry, sizeof *entry);
1929
2278
   }
1930
2279
 
1931
2280
   allocMsg->hdr.dst = VMCI_MAKE_HANDLE(VMCI_HYPERVISOR_CONTEXT_ID,
1932
 
                                        VMCI_QUEUEPAIR_ALLOC);
 
2281
                                        VMCI_QUEUEPAIR_ALLOC);
1933
2282
   allocMsg->hdr.src = VMCI_ANON_SRC_HANDLE;
1934
2283
   allocMsg->hdr.payloadSize = msgSize - VMCI_DG_HEADERSIZE;
1935
2284
   allocMsg->handle = entry->qp.handle;
1995
2344
      return VMCI_ERROR_NO_ACCESS;
1996
2345
   }
1997
2346
 
1998
 
   VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
 
2347
   VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
1999
2348
 
2000
2349
   /* Check if creation/attachment of a queuepair is allowed. */
2001
2350
   if (!VMCI_CanCreate()) {
2052
2401
      goto errorKeepEntry;
2053
2402
   }
2054
2403
 
2055
 
   myProduceQ = VMCI_AllocQueue(produceSize);
 
2404
   myProduceQ = VMCI_AllocQueue(produceSize, flags);
2056
2405
   if (!myProduceQ) {
2057
2406
      VMCI_WARNING((LGPFX"Error allocating pages for produce queue.\n"));
2058
2407
      result = VMCI_ERROR_NO_MEM;
2059
2408
      goto error;
2060
2409
   }
2061
2410
 
2062
 
   myConsumeQ = VMCI_AllocQueue(consumeSize);
 
2411
   myConsumeQ = VMCI_AllocQueue(consumeSize, flags);
2063
2412
   if (!myConsumeQ) {
2064
2413
      VMCI_WARNING((LGPFX"Error allocating pages for consume queue.\n"));
2065
2414
      result = VMCI_ERROR_NO_MEM;
2138
2487
      VMCIQueueHeader_Init((*consumeQ)->qHeader, *handle);
2139
2488
   }
2140
2489
 
2141
 
   VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
2490
   VMCIMutex_Release(&qpGuestEndpoints.mutex);
2142
2491
 
2143
2492
   return VMCI_SUCCESS;
2144
2493
 
2145
2494
error:
2146
 
   VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
2495
   VMCIMutex_Release(&qpGuestEndpoints.mutex);
2147
2496
   if (queuePairEntry) {
2148
2497
      /* The queues will be freed inside the destroy routine. */
2149
2498
      QPGuestEndpointDestroy(queuePairEntry);
2160
2509
errorKeepEntry:
2161
2510
   /* This path should only be used when an existing entry was found. */
2162
2511
   ASSERT(queuePairEntry->qp.refCount > 0);
2163
 
   VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
2512
   VMCIMutex_Release(&qpGuestEndpoints.mutex);
2164
2513
   return result;
2165
2514
}
2166
2515
 
2223
2572
 
2224
2573
   ASSERT(!VMCI_HANDLE_INVALID(handle));
2225
2574
 
2226
 
   VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
 
2575
   VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
2227
2576
 
2228
2577
   entry = (QPGuestEndpoint *)QueuePairList_FindEntry(&qpGuestEndpoints, handle);
2229
2578
   if (!entry) {
2230
 
      VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
2579
      VMCIMutex_Release(&qpGuestEndpoints.mutex);
2231
2580
      return VMCI_ERROR_NOT_FOUND;
2232
2581
   }
2233
2582
 
2275
2624
          * fail?).
2276
2625
          */
2277
2626
 
2278
 
         VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
2627
         VMCIMutex_Release(&qpGuestEndpoints.mutex);
2279
2628
         return result;
2280
2629
      }
2281
2630
   }
2297
2646
                                   * compiler.
2298
2647
                                   */
2299
2648
 
2300
 
   VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
2649
   VMCIMutex_Release(&qpGuestEndpoints.mutex);
2301
2650
 
2302
2651
   if (refCount == 0) {
2303
2652
      QPGuestEndpointDestroy(entry);
2358
2707
 *
2359
2708
 *      Helper function that marks a queue pair entry as not being
2360
2709
 *      converted to a local version during hibernation. Must be
2361
 
 *      called with the queue pair list lock held.
 
2710
 *      called with the queue pair list mutex held.
2362
2711
 *
2363
2712
 * Results:
2364
2713
 *      None.
2491
2840
   if (toLocal) {
2492
2841
      VMCIListItem *next;
2493
2842
 
2494
 
      VMCIQPLock_Acquire(&qpGuestEndpoints.lock);
 
2843
      VMCIMutex_Acquire(&qpGuestEndpoints.mutex);
2495
2844
 
2496
2845
      VMCIList_Scan(next, &qpGuestEndpoints.head) {
2497
2846
         QPGuestEndpoint *entry = (QPGuestEndpoint *)VMCIList_Entry(
2510
2859
            consQ = (VMCIQueue *)entry->consumeQ;
2511
2860
            oldConsQ = oldProdQ = NULL;
2512
2861
 
2513
 
            VMCI_AcquireQueueMutex(prodQ);
 
2862
            VMCI_AcquireQueueMutex(prodQ, TRUE);
2514
2863
 
2515
2864
            result = VMCI_ConvertToLocalQueue(consQ, prodQ,
2516
2865
                                              entry->qp.consumeSize,
2572
2921
      }
2573
2922
      Atomic_Write(&qpGuestEndpoints.hibernate, 1);
2574
2923
 
2575
 
      VMCIQPLock_Release(&qpGuestEndpoints.lock);
 
2924
      VMCIMutex_Release(&qpGuestEndpoints.mutex);
2576
2925
   } else {
2577
2926
      VMCILockFlags flags;
2578
2927
      VMCIHandle handle;