VirtualBox

Changeset 86188 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Sep 21, 2020 8:43:10 AM (4 years ago)
Author:
vboxsync
Message:

Additions/VBoxService: Rework CPU hot-plug code to be more resilient, ticketref:19902 and ticketref19903

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxService/VBoxServiceCpuHotPlug.cpp

    r82968 r86188  
    293293        {
    294294            RTStrFree(pszPath);
     295            pszPath = NULL;
    295296
    296297            /* Search for CPU */
     
    349350                            /* Get the next directory. */
    350351                            RTStrFree(pszPathCurr);
     352                            pszPathCurr = NULL;
    351353                            VGSvcVerbose(3, "CPU doesn't match, next directory\n");
    352354                        }
     
    385387                else
    386388                {
    387                     /* Go back one level and try to get the next entry. */
    388                     Assert(iLvlCurr > 0);
    389 
    390389                    RTDirClose(pAcpiCpuPathLvl->hDir);
    391390                    RTStrFree(pAcpiCpuPathLvl->pszPath);
    392391                    pAcpiCpuPathLvl->hDir = NIL_RTDIR;
    393392                    pAcpiCpuPathLvl->pszPath = NULL;
     393
     394                    /*
     395                     * If we reached the end we didn't find the matching path
     396                     * meaning the CPU is already offline.
     397                     */
     398                    if (!iLvlCurr)
     399                    {
     400                        rc = VERR_NOT_FOUND;
     401                        break;
     402                    }
    394403
    395404                    iLvlCurr--;
     
    436445     * The topology directory (containing the physical and core id properties)
    437446     * is not available until the CPU is online. So we just iterate over all directories
    438      * and enable every CPU which is not online already.
     447     * and enable the first CPU which is not online already.
    439448     * Because the directory might not be available immediately we try a few times.
    440449     *
     
    453462            while (RT_SUCCESS(RTDirRead(hDirDevices, &DirFolderContent, NULL))) /* Assumption that szName has always enough space */
    454463            {
    455                 /** @todo r-bird: This code is bringing all CPUs online; the idCpuCore and
    456                  *        idCpuPackage parameters are unused!
    457                  *        aeichner: These files are not available at this point unfortunately. (see comment above)
    458                  *        bird: Yes, but isn't that easily dealt with by doing:
    459                  *              if (matching_topology() || !have_topology_directory())
    460                  *                  bring_cpu_online()
    461                  *              That could save you the cpu0 and cpuidle checks to.
    462                  */
    463                 /*
    464                  * Check if this is a CPU object.
    465                  * cpu0 is excluded because it is not possible to change the state
    466                  * of the first CPU on Linux (it doesn't even have an online file)
    467                  * and cpuidle is no CPU device. Prevents error messages later.
    468                  */
    469                 if(   !strncmp(DirFolderContent.szName, "cpu", 3)
    470                     && strncmp(DirFolderContent.szName, "cpu0", 4)
    471                     && strncmp(DirFolderContent.szName, "cpuidle", 7))
     464                /* Check if this is a CPU object which can be brought online. */
     465                if (RTLinuxSysFsExists("%s/%s/online", SYSFS_CPU_PATH, DirFolderContent.szName))
    472466                {
    473                     /* Get the sysdev */
    474                     RTFILE hFileCpuOnline = NIL_RTFILE;
    475 
    476                     rc = RTFileOpenF(&hFileCpuOnline, RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
    477                                      "%s/%s/online", SYSFS_CPU_PATH, DirFolderContent.szName);
    478                     if (RT_SUCCESS(rc))
     467                    /* Check the status of the CPU by reading the online flag. */
     468                    int64_t i64Status = 0;
     469                    rc = RTLinuxSysFsReadIntFile(10 /*uBase*/, &i64Status, "%s/%s/online", SYSFS_CPU_PATH, DirFolderContent.szName);
     470                    if (   RT_SUCCESS(rc)
     471                        && i64Status == 0)
    479472                    {
    480                         /* Write a 1 to online the CPU */
    481                         rc = RTFileWrite(hFileCpuOnline, "1", 1, NULL);
    482                         RTFileClose(hFileCpuOnline);
     473                        /* CPU is offline, turn it on. */
     474                        rc = RTLinuxSysFsWriteU8File(10 /*uBase*/, 1, "%s/%s/online", SYSFS_CPU_PATH, DirFolderContent.szName);
    483475                        if (RT_SUCCESS(rc))
    484476                        {
     
    487479                            break;
    488480                        }
    489                         /* Error means CPU not present or online already  */
    490481                    }
    491                     else
     482                    else if (RT_FAILURE(rc))
    492483                        VGSvcError("CpuHotPlug: Failed to open '%s/%s/online' rc=%Rrc\n",
    493484                                   SYSFS_CPU_PATH, DirFolderContent.szName, rc);
     485                    else
     486                    {
     487                        /*
     488                         * Check whether the topology matches what we got (which means someone raced us and brought the CPU
     489                         * online already).
     490                         */
     491                        int64_t i64Core    = 0;
     492                        int64_t i64Package = 0;
     493
     494                        int rc2 = RTLinuxSysFsReadIntFile(10, &i64Core, "%s/%s/topology/core_id",
     495                                                          SYSFS_CPU_PATH, DirFolderContent.szName);
     496                        if (RT_SUCCESS(rc2))
     497                            rc2 = RTLinuxSysFsReadIntFile(10, &i64Package, "%s/%s/topology/physical_package_id",
     498                                                          SYSFS_CPU_PATH, DirFolderContent.szName);
     499                        if (   RT_SUCCESS(rc2)
     500                            && idCpuPackage == i64Package
     501                            && idCpuCore == i64Core)
     502                        {
     503                            VGSvcVerbose(1, "CpuHotPlug: '%s' is already online\n", DirFolderContent.szName);
     504                            fCpuOnline = true;
     505                            break;
     506                        }
     507                    }
    494508                }
    495509            }
     
    501515        /* Sleep a bit */
    502516        if (!fCpuOnline)
    503             RTThreadSleep(10);
     517            RTThreadSleep(100);
    504518
    505519    } while (   !fCpuOnline
     
    541555        RTStrFree(pszCpuDevicePath);
    542556    }
     557    else if (rc == VERR_NOT_FOUND)
     558        VGSvcVerbose(1, "CpuHotPlug: CPU %u/%u was aleady ejected by someone else!\n", idCpuPackage, idCpuCore);
    543559    else
    544560        VGSvcError("CpuHotPlug: Failed to get CPU device path rc=%Rrc\n", rc);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette