VirtualBox

Changeset 64605 in vbox for trunk


Ignore:
Timestamp:
Nov 8, 2016 6:27:27 PM (8 years ago)
Author:
vboxsync
Message:

TestBoxHelper.cpp: Added wipefreespace command for use before backing up a testbox.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/testboxscript/TestBoxHelper.cpp

    r62484 r64605  
    3131#include <iprt/buildconfig.h>
    3232#include <iprt/env.h>
     33#include <iprt/file.h>
     34#include <iprt/path.h>
     35#include <iprt/getopt.h>
    3336#include <iprt/initterm.h>
     37#include <iprt/mem.h>
    3438#include <iprt/message.h>
    3539#include <iprt/mp.h>
     
    4751# include <sys/sysctl.h>
    4852#endif
     53
     54
     55
     56/**
     57 * Does one free space wipe, using the given filename.
     58 *
     59 * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE on failure (fully
     60 *          bitched).
     61 * @param   pszFilename     The filename to use for wiping free space.  Will be
     62 *                          replaced and afterwards deleted.
     63 * @param   pvFiller        The filler block buffer.
     64 * @param   cbFiller        The size of the filler block buffer.
     65 * @param   cbMinLeftOpt    When to stop wiping.
     66 */
     67static RTEXITCODE doOneFreeSpaceWipe(const char *pszFilename, void const *pvFiller, size_t cbFiller, uint64_t cbMinLeftOpt)
     68{
     69    /*
     70     * Open the file.
     71     */
     72    RTEXITCODE  rcExit = RTEXITCODE_SUCCESS;
     73    RTFILE      hFile  = NIL_RTFILE;
     74    int rc = RTFileOpen(&hFile, pszFilename,
     75                        RTFILE_O_WRITE | RTFILE_O_DENY_NONE | RTFILE_O_CREATE_REPLACE | (0775 << RTFILE_O_CREATE_MODE_SHIFT));
     76    if (RT_SUCCESS(rc))
     77    {
     78        /*
     79         * Query the amount of available free space.  Figure out which API we should use.
     80         */
     81        RTFOFF cbTotal = 0;
     82        RTFOFF cbFree = 0;
     83        rc = RTFileQueryFsSizes(hFile, &cbTotal, &cbFree, NULL, NULL);
     84        bool const fFileHandleApiSupported = rc != VERR_NOT_SUPPORTED && rc != VERR_NOT_IMPLEMENTED;
     85        if (!fFileHandleApiSupported)
     86            rc = RTFsQuerySizes(pszFilename, &cbTotal, &cbFree, NULL, NULL);
     87        if (RT_SUCCESS(rc))
     88        {
     89            RTPrintf("%s: %'RTfoff bytes out of  %'RTfoff are free\n", pszFilename, cbFree, cbTotal);
     90
     91            /*
     92             * Start filling up the free space, down to the last 32MB.
     93             */
     94            RTFOFF const    cbMinLeft     = RT_MAX(cbMinLeftOpt, cbFiller * 2);
     95            RTFOFF          cbLeftToWrite = cbFree - cbMinLeft;
     96            uint64_t        cbWritten     = 0;
     97            uint32_t        iLoop         = 0;
     98            while (cbLeftToWrite >= (RTFOFF)cbFiller)
     99            {
     100                rc = RTFileWrite(hFile, pvFiller, cbFiller, NULL);
     101                if (RT_FAILURE(rc))
     102                {
     103                    if (rc == VERR_DISK_FULL)
     104                        RTPrintf("%s: Disk full after writing %'RU64 bytes\n", pszFilename, cbWritten);
     105                    else
     106                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Write error after %'RU64 bytes: %Rrc\n",
     107                                                pszFilename, cbWritten, rc);
     108                    break;
     109                }
     110
     111                /* Flush every now and then as we approach a completely full disk. */
     112                if (cbLeftToWrite <= _1G && (iLoop & (cbLeftToWrite  > _128M ? 15 : 3)) == 0)
     113                    RTFileFlush(hFile);
     114
     115                /*
     116                 * Advance and maybe recheck the amount of free space.
     117                 */
     118                cbWritten     += cbFiller;
     119                cbLeftToWrite -= (ssize_t)cbFiller;
     120                iLoop++;
     121                if ((iLoop & (16 - 1)) == 0 || cbLeftToWrite < _256M)
     122                {
     123                    RTFOFF cbFreeUpdated;
     124                    if (fFileHandleApiSupported)
     125                        rc = RTFsQuerySizes(pszFilename, NULL, &cbFreeUpdated, NULL, NULL);
     126                    else
     127                        rc = RTFileQueryFsSizes(hFile, NULL, &cbFreeUpdated, NULL, NULL);
     128                    if (RT_SUCCESS(rc))
     129                    {
     130                        cbFree = cbFreeUpdated;
     131                        cbLeftToWrite = cbFree - cbMinLeft;
     132                    }
     133                    else
     134                    {
     135                        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to query free space after %'RU64 bytes: %Rrc\n",
     136                                                pszFilename, cbWritten, rc);
     137                        break;
     138                    }
     139                    if ((iLoop & (512 - 1)) == 0)
     140                        RTPrintf("%s: %'RTfoff bytes out of  %'RTfoff are free after writing  %'RU64 bytes\n",
     141                                 pszFilename, cbFree, cbTotal, cbWritten);
     142                }
     143            }
     144
     145            /*
     146             * Now flush the file and then reduce the size a little before closing
     147             * it so the system won't entirely run out of space.  The flush should
     148             * ensure the data has actually hit the disk.
     149             */
     150            rc = RTFileFlush(hFile);
     151            if (RT_FAILURE(rc))
     152                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Flush failed at %'RU64 bytes: %Rrc\n", pszFilename, cbWritten, rc);
     153
     154            uint64_t cbReduced = cbWritten > _512M ? cbWritten - _512M : cbWritten / 2;
     155            rc = RTFileSetAllocationSize(hFile, cbReduced, RTFILE_ALLOC_SIZE_F_DEFAULT);
     156            if (RT_FAILURE(rc))
     157                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Failed to reduce file size from %'RU64 to %'RU64 bytes: %Rrc\n",
     158                                        pszFilename, cbWritten, cbReduced, rc);
     159        }
     160        else
     161            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Initial free space query failed: %Rrc \n", pszFilename, rc);
     162
     163        RTFileClose(hFile);
     164
     165        /*
     166         * Delete the file.
     167         */
     168        rc = RTFileDelete(pszFilename);
     169        if (RT_FAILURE(rc))
     170            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Delete failed: %Rrc !!\n", pszFilename, rc);
     171    }
     172    else
     173        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "%s: Open failed: %Rrc\n", pszFilename, rc);
     174    return rcExit;
     175}
     176
     177
     178/**
     179 * Wipes free space on one or more volumes by creating large files.
     180 */
     181static RTEXITCODE handlerWipeFreeSpace(int argc, char **argv)
     182{
     183    /*
     184     * Parse arguments.
     185     */
     186    const char *apszDefFiles[2] = { "./wipefree.spc", NULL };
     187    bool        fAll            = false;
     188    uint32_t    u32Filler       = UINT32_C(0xf6f6f6f6);
     189    uint64_t    cbMinLeftOpt    = _32M;
     190
     191    static RTGETOPTDEF const s_aOptions[] =
     192    {
     193        { "--all",      'a', RTGETOPT_REQ_NOTHING },
     194        { "--filler",   'f', RTGETOPT_REQ_UINT32 },
     195        { "--min-free", 'm', RTGETOPT_REQ_UINT64 },
     196    };
     197    RTGETOPTSTATE State;
     198    RTGetOptInit(&State, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
     199    RTGETOPTUNION ValueUnion;
     200    int chOpt;
     201    while (  (chOpt = RTGetOpt(&State, &ValueUnion)) != 0
     202           && chOpt != VINF_GETOPT_NOT_OPTION)
     203    {
     204        switch (chOpt)
     205        {
     206            case 'a':
     207                fAll = true;
     208                break;
     209            case 'f':
     210                u32Filler = ValueUnion.u32;
     211                break;
     212            case 'm':
     213                cbMinLeftOpt = ValueUnion.u64;
     214                break;
     215            case 'h':
     216                RTPrintf("usage: wipefrespace [options] [filename1 [..]]\n",
     217                         "\n"
     218                         "Options:\n"
     219                         "  -a, --all\n"
     220                         "    Try do the free space wiping on all seemingly relevant file systems.\n"
     221                         "    Changes the meaning of the filenames  "
     222                         "    This is not yet implemented\n"
     223                         "  -p, --filler <32-bit value>\n"
     224                         "    What to fill the blocks we write with.  Default: 0xf6f6f6f6\n"
     225                         "  -m, --min-free <64-bit byte count>\n"
     226                         "    Specifies when to stop in terms of free disk space (in bytes).\n"
     227                         "    Default: 32MB\n"
     228                         "\n"
     229                         "Zero or more names of files to do the free space wiping thru can be given.\n"
     230                         "When --all is NOT used, each of the files are used to do free space wiping on\n"
     231                         "the volume they will live on.  However, when --all is in effect the files are\n"
     232                         "appended to the volume mountpoints and only the first that can be created will\n"
     233                         "be used.  Files (used ones) will be removed when done.\n"
     234                         );
     235                return RTEXITCODE_SUCCESS;
     236
     237            default:
     238                return RTGetOptPrintError(chOpt, &ValueUnion);
     239        }
     240    }
     241
     242    char **papszFiles;
     243    if (chOpt == 0)
     244        papszFiles = (char **)apszDefFiles;
     245    else
     246        papszFiles = RTGetOptNonOptionArrayPtr(&State);
     247
     248    /*
     249     * Allocate and prep a memory which we'll write over and over again.
     250     */
     251    uint32_t  cbFiller   = _2M;
     252    uint32_t *pu32Filler = (uint32_t *)RTMemPageAlloc(cbFiller);
     253    while (!pu32Filler)
     254    {
     255        cbFiller <<= 1;
     256        if (cbFiller >= _4K)
     257            pu32Filler = (uint32_t *)RTMemPageAlloc(cbFiller);
     258        else
     259            return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTMemPageAlloc failed for sizes between 4KB and 2MB!\n");
     260    }
     261    for (uint32_t i = 0; i < cbFiller / sizeof(pu32Filler[0]); i++)
     262        pu32Filler[i] = u32Filler;
     263
     264    /*
     265     * Do the requested work.
     266     */
     267    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     268    if (!fAll)
     269    {
     270        for (uint32_t iFile = 0; papszFiles[iFile] != NULL; iFile++)
     271        {
     272            RTEXITCODE rcExit2 = doOneFreeSpaceWipe(papszFiles[iFile], pu32Filler, cbFiller, cbMinLeftOpt);
     273            if (rcExit2 != RTEXITCODE_SUCCESS && rcExit == RTEXITCODE_SUCCESS)
     274                rcExit = rcExit2;
     275        }
     276    }
     277    else
     278    {
     279        /*
     280         * Reject --all for now.
     281         */
     282        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE,  "The --all option is not yet implemented!\n");
     283    }
     284
     285    RTMemPageFree(pu32Filler, cbFiller);
     286    return rcExit;
     287}
    49288
    50289
     
    395634        { "longmode",       handlerCpuLongMode,     true },
    396635        { "memsize",        handlerMemSize,         true },
    397         { "report",         handlerReport,          true }
     636        { "report",         handlerReport,          true },
     637        { "wipefreespace",  handlerWipeFreeSpace,   false }
    398638    };
    399639
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