VirtualBox

Changeset 29503 in vbox


Ignore:
Timestamp:
May 16, 2010 1:20:10 PM (15 years ago)
Author:
vboxsync
Message:

Additions/CpuHotplug: Rewrite method to get the path to the CPU object in /sys for ejection because the path differs between the different kernel versions and dstributions. It is much easier now to add a change

File:
1 edited

Legend:

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

    r28800 r29503  
    4141 * @{
    4242 */
    43 # define SYSFS_ACPI_CPU_PATH    "/sys/devices/LNXSYSTM:00/device:00"
     43# define SYSFS_ACPI_CPU_PATH    "/sys/devices"
    4444# define SYSFS_CPU_PATH         "/sys/devices/system/cpu"
    4545/** @} */
     46
     47/** Path component for the ACPI CPU path. */
     48typedef struct SYSFSCPUPATHCOMP
     49{
     50    /** Flag whether the name is suffixed with a number */
     51    bool        fNumberedSuffix;
     52    /** Name of the component */
     53    const char *pcszName;
     54} SYSFSCPUPATHCOMP, *PSYSFSCPUPATHCOMP;
     55/** Pointer to a const component. */
     56typedef const SYSFSCPUPATHCOMP *PCSYSFSCPUPATHCOMP;
     57
     58/**
     59 * Structure which defines how the entries are assembled.
     60 */
     61typedef struct SYSFSCPUPATH
     62{
     63    /** Id when probing for the correct path. */
     64    uint32_t           uId;
     65    /** Array holding the possible components. */
     66    PCSYSFSCPUPATHCOMP aComponentsPossible;
     67    /** Number of entries in the array, excluding the terminator. */
     68    unsigned           cComponents;
     69    /** Directory handle */
     70    PRTDIR             pDir;
     71    /** Current directory to try. */
     72    char              *pszPath;
     73} SYSFSCPUPATH, *PSYSFSCPUPATH;
     74
     75/** Content of uId if the path wasn't probed yet. */
     76#define ACPI_CPU_PATH_NOT_PROBED UINT32_MAX
     77
     78/** Possible combinations of all path components for level 1. */
     79const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl1[] =
     80{
     81    /** LNXSYSTEM:<id> */
     82    {true, "LNXSYSTM:"}
     83};
     84
     85/** Possible combinations of all path components for level 2. */
     86const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl2[] =
     87{
     88    /** device:<id> */
     89    {true, "device:"},
     90    /** LNXSYBUS:<id> */
     91    {true, "LNXSYBUS:"}
     92};
     93
     94/** Possible combinations of all path components for level 3 */
     95const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl3[] =
     96{
     97    /** ACPI0004:<id> */
     98    {true, "ACPI0004:"}
     99};
     100
     101/** Possible combinations of all path components for level 4 */
     102const SYSFSCPUPATHCOMP g_aAcpiCpuPathLvl4[] =
     103{
     104    /** LNXCPU:<id> */
     105    {true, "LNXCPU:"},
     106    /** ACPI_CPU:<id> */
     107    {true, "ACPI_CPU:"}
     108};
     109
     110/** All possible combinations. */
     111SYSFSCPUPATH g_aAcpiCpuPath[] =
     112{
     113    /** Level 1 */
     114    {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl1, RT_ELEMENTS(g_aAcpiCpuPathLvl1), NULL, NULL},
     115    /** Level 2 */
     116    {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl2, RT_ELEMENTS(g_aAcpiCpuPathLvl2), NULL, NULL},
     117    /** Level 3 */
     118    {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl3, RT_ELEMENTS(g_aAcpiCpuPathLvl3), NULL, NULL},
     119    /** Level 4 */
     120    {ACPI_CPU_PATH_NOT_PROBED, g_aAcpiCpuPathLvl4, RT_ELEMENTS(g_aAcpiCpuPathLvl4), NULL, NULL},
     121};
    46122#endif
    47123
    48 
    49124#ifdef RT_OS_LINUX
     125/**
     126 * Probes for the correct path to the ACPI CPU object in sysfs for the
     127 * various different kernel versions and distro's.
     128 *
     129 * @returns VBox status code.
     130 */
     131static int VBoxServiceCpuHotPlugProbePath(void)
     132{
     133    int rc = VINF_SUCCESS;
     134
     135    /* Probe for the correct path if we didn't already. */
     136    if (RT_UNLIKELY(g_aAcpiCpuPath[0].uId == ACPI_CPU_PATH_NOT_PROBED))
     137    {
     138        char *pszPath = NULL;   /** < Current path, increasing while we dig deeper. */
     139
     140        pszPath = RTStrDup(SYSFS_ACPI_CPU_PATH);
     141        if (!pszPath)
     142            return VERR_NO_MEMORY;
     143
     144        /*
     145         * Simple algorithm to find the path.
     146         * Performance is not a real problem because it is
     147         * only executed once.
     148         */
     149        for (unsigned iLvlCurr = 0; iLvlCurr < RT_ELEMENTS(g_aAcpiCpuPath); iLvlCurr++)
     150        {
     151            PSYSFSCPUPATH pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr];
     152
     153            for (unsigned iCompCurr = 0; iCompCurr < pAcpiCpuPathLvl->cComponents; iCompCurr++)
     154            {
     155                PCSYSFSCPUPATHCOMP pPathComponent = &pAcpiCpuPathLvl->aComponentsPossible[iCompCurr];
     156                PRTDIR pDirCurr = NULL;
     157                char *pszPathTmp = NULL;
     158                bool fFound = false;
     159
     160                rc = RTStrAPrintf(&pszPathTmp, "%s/%s*", pszPath, pPathComponent->pcszName);
     161                if (RT_FAILURE(rc))
     162                    break;
     163
     164                /* Open the directory */
     165                rc = RTDirOpenFiltered(&pDirCurr, pszPathTmp, RTDIRFILTER_WINNT);
     166                if (RT_FAILURE(rc))
     167                {
     168                    RTStrFree(pszPathTmp);
     169                    break;
     170                }
     171
     172                /* Search if the current directory contains one of the possible parts. */
     173                RTDIRENTRY DirFolderContent;
     174                while (RT_SUCCESS(RTDirRead(pDirCurr, &DirFolderContent, NULL))) /* Assumption that szName has always enough space */
     175                {
     176                    if (!strncmp(DirFolderContent.szName, pPathComponent->pcszName, strlen(pPathComponent->pcszName)))
     177                    {
     178                        char *pszPathLvl = NULL;
     179
     180                        /* Found, use the complete name to dig deeper. */
     181                        fFound = true;
     182                        pAcpiCpuPathLvl->uId = iCompCurr;
     183                        rc = RTStrAPrintf(&pszPathLvl, "%s/%s", pszPath, DirFolderContent.szName);
     184
     185                        if (RT_SUCCESS(rc))
     186                        {
     187                            RTStrFree(pszPath);
     188                            pszPath = pszPathLvl;
     189                        }
     190                        break;
     191                    }
     192                }
     193                RTDirClose(pDirCurr);
     194
     195                if (fFound)
     196                    break;
     197            } /* For every possible component. */
     198
     199            /* No matching component for this part, no need to continue */
     200            if (RT_FAILURE(rc))
     201                break;
     202        } /* For every level */
     203
     204        VBoxServiceVerbose(1, "Final path after probing %s rc=%Rrc\n", pszPath, rc);
     205        RTStrFree(pszPath);
     206    }
     207
     208    return rc;
     209}
     210
    50211/**
    51212 * Returns the path of the ACPI CPU device with the given core and package ID.
     
    58219static int VBoxServiceCpuHotPlugGetACPIDevicePath(char **ppszPath, uint32_t idCpuCore, uint32_t idCpuPackage)
    59220{
    60     AssertPtr(ppszPath);
    61 
    62     PRTDIR pDirDevices = NULL;
    63     int rc = RTDirOpen(&pDirDevices, SYSFS_ACPI_CPU_PATH);  /* could use RTDirOpenFiltered */
     221    int rc = VINF_SUCCESS;
     222
     223    AssertPtrReturn(ppszPath, VERR_INVALID_PARAMETER);
     224
     225    rc = VBoxServiceCpuHotPlugProbePath();
    64226    if (RT_SUCCESS(rc))
    65227    {
    66         /* Search every ACPI0004 container device for LNXCPU devices. */
    67         RTDIRENTRY DirFolderAcpiContainer;
     228        /* Build the path from all components. */
    68229        bool fFound = false;
    69 
    70         while (   RT_SUCCESS(RTDirRead(pDirDevices, &DirFolderAcpiContainer, NULL))
    71                && !fFound) /* Assumption that szName has always enough space */
     230        unsigned iLvlCurr = 0;
     231        char *pszPath = NULL;
     232        char *pszPathDir = NULL;
     233        PSYSFSCPUPATH pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr];
     234
     235        /* Init everything. */
     236        Assert(pAcpiCpuPathLvl->uId != ACPI_CPU_PATH_NOT_PROBED);
     237        rc = RTStrAPrintf(&pszPath,
     238                          "%s/%s*", SYSFS_ACPI_CPU_PATH,
     239                          pAcpiCpuPathLvl->aComponentsPossible[pAcpiCpuPathLvl->uId].pcszName);
     240        if (RT_FAILURE(rc))
     241            return rc;
     242
     243        pAcpiCpuPathLvl->pszPath = RTStrDup(SYSFS_ACPI_CPU_PATH);
     244        if (!pAcpiCpuPathLvl->pszPath)
     245            return VERR_NO_MEMORY;
     246
     247        /* Open the directory */
     248        rc = RTDirOpenFiltered(&pAcpiCpuPathLvl->pDir, pszPath, RTDIRFILTER_WINNT);
     249        if (RT_SUCCESS(rc))
    72250        {
    73             if (!strncmp(DirFolderAcpiContainer.szName, "ACPI0004", 8))
     251            RTStrFree(pszPath);
     252
     253            /* Search for CPU */
     254            while (!fFound)
    74255            {
    75                 char *pszAcpiContainerPath = NULL;
    76                 PRTDIR pDirAcpiContainer = NULL;
    77 
    78                 rc = RTStrAPrintf(&pszAcpiContainerPath, "%s/%s", SYSFS_ACPI_CPU_PATH, DirFolderAcpiContainer.szName);
    79                 if (RT_FAILURE(rc))
    80                     break;
    81 
    82                 rc = RTDirOpen(&pDirAcpiContainer, pszAcpiContainerPath);
     256                /* Get the next directory. */
     257                RTDIRENTRY DirFolderContent;
     258                rc = RTDirRead(pAcpiCpuPathLvl->pDir, &DirFolderContent, NULL);
    83259                if (RT_SUCCESS(rc))
    84260                {
    85                     RTDIRENTRY DirFolderContent;
    86                     while (RT_SUCCESS(RTDirRead(pDirAcpiContainer, &DirFolderContent, NULL))) /* Assumption that szName has always enough space */
     261                    char *pszPathCurr;
     262
     263                    /* Create the new path. */
     264                    rc = RTStrAPrintf(&pszPathCurr, "%s/%s", pAcpiCpuPathLvl->pszPath, DirFolderContent.szName);
     265                    if (RT_FAILURE(rc))
     266                        break;
     267
     268                    /* If this is the last level check for the given core and package id. */
     269                    if (iLvlCurr == RT_ELEMENTS(g_aAcpiCpuPath) - 1)
    87270                    {
    88                         if (   !strncmp(DirFolderContent.szName, "LNXCPU", 6)
    89                             || !strncmp(DirFolderContent.szName, "ACPI_CPU", 8))
     271                        /* Get the sysdev */
     272                        uint32_t idCore    = RTLinuxSysFsReadIntFile(10, "%s/sysdev/topology/core_id",
     273                                                                     pszPathCurr);
     274                        uint32_t idPackage = RTLinuxSysFsReadIntFile(10, "%s/sysdev/topology/physical_package_id",
     275                                                                     pszPathCurr);
     276                        if (   idCore    == idCpuCore
     277                            && idPackage == idCpuPackage)
    90278                        {
    91                             /* Get the sysdev */
    92                             uint32_t idCore    = RTLinuxSysFsReadIntFile(10, "%s/%s/sysdev/topology/core_id",
    93                                                                          pszAcpiContainerPath, DirFolderContent.szName);
    94                             uint32_t idPackage = RTLinuxSysFsReadIntFile(10, "%s/%s/sysdev/topology/physical_package_id",
    95                                                                          pszAcpiContainerPath, DirFolderContent.szName);
    96                             if (   idCore    == idCpuCore
    97                                 && idPackage == idCpuPackage)
    98                             {
    99                                 /* Return the path */
    100                                 rc = RTStrAPrintf(ppszPath, "%s/%s", pszAcpiContainerPath, DirFolderContent.szName);
    101                                 fFound = true;
    102                                 break;
    103                             }
     279                            /* Return the path */
     280                            pszPath = pszPathCurr;
     281                            fFound = true;
     282                            VBoxServiceVerbose(3, "CPU found\n");
     283                            break;
     284                        }
     285                        else
     286                        {
     287                            /* Get the next directory. */
     288                            RTStrFree(pszPathCurr);
     289                            VBoxServiceVerbose(3, "CPU doesn't match, next directory\n");
    104290                        }
    105291                    }
    106 
    107                     RTDirClose(pDirAcpiContainer);
     292                    else
     293                    {
     294                        /* Go deeper */
     295                        iLvlCurr++;
     296
     297                        VBoxServiceVerbose(3, "Going deeper (iLvlCurr=%u)\n", iLvlCurr);
     298
     299                        pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr];
     300
     301                        Assert(!pAcpiCpuPathLvl->pDir);
     302                        Assert(!pAcpiCpuPathLvl->pszPath);
     303                        pAcpiCpuPathLvl->pszPath = pszPathCurr;
     304                        PCSYSFSCPUPATHCOMP pPathComponent = &pAcpiCpuPathLvl->aComponentsPossible[pAcpiCpuPathLvl->uId];
     305
     306                        Assert(pAcpiCpuPathLvl->uId != ACPI_CPU_PATH_NOT_PROBED);
     307
     308                        rc = RTStrAPrintf(&pszPathDir, "%s/%s*", pszPathCurr, pPathComponent->pcszName);
     309                        if (RT_FAILURE(rc))
     310                            break;
     311
     312                        VBoxServiceVerbose(3, "New path %s\n", pszPathDir);
     313
     314                        /* Open the directory */
     315                        rc = RTDirOpenFiltered(&pAcpiCpuPathLvl->pDir, pszPathDir, RTDIRFILTER_WINNT);
     316                        if (RT_FAILURE(rc))
     317                            break;
     318                    }
    108319                }
    109 
    110                 RTStrFree(pszAcpiContainerPath);
    111             }
     320                else
     321                {
     322                    /* Go back one level and try to get the next entry. */
     323                    Assert(iLvlCurr > 0);
     324
     325                    RTDirClose(pAcpiCpuPathLvl->pDir);
     326                    RTStrFree(pAcpiCpuPathLvl->pszPath);
     327                    pAcpiCpuPathLvl->pDir = NULL;
     328                    pAcpiCpuPathLvl->pszPath = NULL;
     329
     330                    iLvlCurr--;
     331                    pAcpiCpuPathLvl = &g_aAcpiCpuPath[iLvlCurr];
     332                    VBoxServiceVerbose(3, "Directory not found, going back (iLvlCurr=%u)\n", iLvlCurr);
     333                }
     334            } /* while not found */
     335        } /* Successful init */
     336
     337        /* Cleanup */
     338        for (unsigned i = 0; i < RT_ELEMENTS(g_aAcpiCpuPath); i++)
     339        {
     340            if (g_aAcpiCpuPath[i].pDir)
     341                RTDirClose(g_aAcpiCpuPath[i].pDir);
     342            if (g_aAcpiCpuPath[i].pszPath)
     343                RTStrFree(g_aAcpiCpuPath[i].pszPath);
     344            g_aAcpiCpuPath[i].pDir = NULL;
     345            g_aAcpiCpuPath[i].pszPath = NULL;
    112346        }
    113 
    114         RTDirClose(pDirDevices);
     347        if (pszPathDir)
     348            RTStrFree(pszPathDir);
     349        if (RT_FAILURE(rc) && pszPath)
     350            RTStrFree(pszPath);
     351
     352        if (RT_SUCCESS(rc))
     353            *ppszPath = pszPath;
    115354    }
    116355
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