gfp_t priority, unsigned short type);
#endif
static void VSockVmciTestUnregister(void);
+static int VSockVmciRegisterWithVmci(void);
+static void VSockVmciUnregisterWithVmci(void);
static int VSockVmciRegisterAddressFamily(void);
static void VSockVmciUnregisterAddressFamily(void);
{
int err = 0;
int i;
+
+ /*
+ * Linux will not allocate an address family to code that is not part of the
+ * kernel proper, so until that time comes we need a workaround. Here we
+ * loop through the allowed values and claim the first one that's not
+ * currently used. Users will then make an ioctl(2) into our module to
+ * retrieve this value before calling socket(2).
+ *
+ * This is undesirable, but it's better than having users' programs break
+ * when a hard-coded, currently-available value gets assigned to someone
+ * else in the future.
+ */
+ for (i = NPROTO - 1; i >= 0; i--) {
+ vsockVmciFamilyOps.family = i;
+ err = sock_register(&vsockVmciFamilyOps);
+ if (err) {
+ Warning("Could not register address family %d.\n", i);
+ vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY;
+ } else {
+ vsockVmciDgramOps.family = i;
+ vsockVmciStreamOps.family = i;
+ err = i;
+ break;
+ }
+ }
+
+ return err;
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciUnregisterAddressFamily --
+ *
+ * Unregisters the address family with the kernel.
+ *
+ * Note that this assumes the registration lock is held.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Our socket implementation is no longer accessible.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static void
+VSockVmciUnregisterAddressFamily(void)
+{
+ if (vsockVmciFamilyOps.family != VSOCK_INVALID_FAMILY) {
+ sock_unregister(vsockVmciFamilyOps.family);
+ }
+
+ vsockVmciDgramOps.family = vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY;
+ vsockVmciStreamOps.family = vsockVmciFamilyOps.family;
+}
+
+
+
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * VSockVmciRegisterWithVmci --
+ *
+ * Registers with the VMCI device, and creates control message
+ * and event handlers.
+ *
+ * Results:
+ * Zero on success, error code on failure.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------------
+ */
+
+static int
+VSockVmciRegisterWithVmci(void)
+{
+ int err = 0;
uint32 apiVersion;
/*
- * We don't call into the vmci module or register our socket family if the
- * vmci device isn't present.
+ * We don't call into the vmci module if the vmci device isn't
+ * present.
*/
apiVersion = VMCI_KERNEL_API_VERSION_1;
vmciDevicePresent = VMCI_DeviceGet(&apiVersion);
if (!vmciDevicePresent) {
- Log("Could not register VMCI Sockets because VMCI device is not present "
- "or API version is unsupported.\n");
+ Warning("VMCI device not present.\n");
return -1;
}
TRUE);
if (err < VMCI_SUCCESS) {
Warning("Unable to create datagram handle. (%d)\n", err);
- goto error;
+ err = VSockVmci_ErrorToVSockError(err);
+ goto out;
}
err = VMCIEvent_Subscribe(VMCI_EVENT_QP_RESUMED,
Warning("Unable to subscribe to QP resumed event. (%d)\n", err);
err = VSockVmci_ErrorToVSockError(err);
qpResumedSubId = VMCI_INVALID_ID;
- goto error;
- }
-
- /*
- * Linux will not allocate an address family to code that is not part of the
- * kernel proper, so until that time comes we need a workaround. Here we
- * loop through the allowed values and claim the first one that's not
- * currently used. Users will then make an ioctl(2) into our module to
- * retrieve this value before calling socket(2).
- *
- * This is undesirable, but it's better than having users' programs break
- * when a hard-coded, currently-available value gets assigned to someone
- * else in the future.
- */
- for (i = NPROTO - 1; i >= 0; i--) {
- vsockVmciFamilyOps.family = i;
- err = sock_register(&vsockVmciFamilyOps);
- if (err) {
- Warning("Could not register address family %d.\n", i);
- vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY;
- } else {
- vsockVmciDgramOps.family = i;
- vsockVmciStreamOps.family = i;
- break;
- }
- }
-
- if (err) {
- goto error;
+ goto out;
}
- return vsockVmciFamilyOps.family;
-
-error:
- if (qpResumedSubId != VMCI_INVALID_ID) {
- VMCIEvent_Unsubscribe(qpResumedSubId);
- qpResumedSubId = VMCI_INVALID_ID;
+out:
+ if (err != 0) {
+ VSockVmciUnregisterWithVmci();
}
- if (!VMCI_HANDLE_INVALID(vmciStreamHandle)) {
- VMCIDatagram_DestroyHnd(vmciStreamHandle);
- vmciStreamHandle = VMCI_INVALID_HANDLE;
- }
return err;
}
/*
*----------------------------------------------------------------------------
*
- * VSockVmciUnregisterAddressFamily --
+ * VSockVmciUnregisterWithVmci --
*
- * Unregisters the address family with the kernel.
- *
- * Note that this assumes the registration lock is held.
+ * Destroys control message and event handlers, and unregisters
+ * with the VMCI device
*
* Results:
* None.
*/
static void
-VSockVmciUnregisterAddressFamily(void)
+VSockVmciUnregisterWithVmci(void)
{
if (!vmciDevicePresent) {
/* Nothing was registered. */
qpResumedSubId = VMCI_INVALID_ID;
}
- if (vsockVmciFamilyOps.family != VSOCK_INVALID_FAMILY) {
- sock_unregister(vsockVmciFamilyOps.family);
- }
-
- vsockVmciDgramOps.family = vsockVmciFamilyOps.family = VSOCK_INVALID_FAMILY;
- vsockVmciStreamOps.family = vsockVmciFamilyOps.family;
-
VMCI_DeviceRelease();
+ vmciDevicePresent = FALSE;
}
return err;
}
+ err = VSockVmciRegisterWithVmci();
+ if (err) {
+ Warning("Cannot register with VMCI device.\n");
+ unregister_ioctl32_handlers();
+ misc_deregister(&vsockVmciDevice);
+ return err;
+ }
+
err = VSockVmciRegisterProto();
if (err) {
Warning("Cannot register vsock protocol.\n");
+ VSockVmciUnregisterWithVmci();
unregister_ioctl32_handlers();
misc_deregister(&vsockVmciDevice);
return err;
compat_mutex_unlock(®istrationMutex);
VSockVmciUnregisterProto();
+ VSockVmciUnregisterWithVmci();
}