Ticket #3723: vm_kernel_17082011.patch

File vm_kernel_17082011.patch, 8.4 KB (added by hamish, 13 years ago)

Swap volume support in kernel for #3723

  • src/system/kernel/vm/VMAnonymousCache.cpp

     
    1717#include <string.h>
    1818#include <unistd.h>
    1919
     20#include <FindDirectory.h>
    2021#include <KernelExport.h>
    2122#include <NodeMonitor.h>
    2223
    2324#include <arch_config.h>
    2425#include <boot_device.h>
     26#include <disk_device_manager/KDiskDevice.h>
     27#include <disk_device_manager/KDiskDeviceManager.h>
     28#include <disk_device_manager/KDiskSystem.h>
     29#include <disk_device_manager/KPartitionVisitor.h>
    2530#include <driver_settings.h>
    2631#include <fs/fd.h>
     32#include <fs/KPath.h>
     33#include <fs_info.h>
    2734#include <fs_interface.h>
    2835#include <heap.h>
    2936#include <kernel_daemon.h>
     
    5360#   define TRACE(x...) do { } while (false)
    5461#endif
    5562
     63static const char* const kDefaultSwapPath = "/var/swap";
     64static const char* const kSwapErrorFilePath = "swaperr";
    5665
    5766// number of free swap blocks the object cache shall minimally have
    5867#define MIN_SWAP_BLOCK_RESERVE  4096
     
    13231332}
    13241333
    13251334
     1335struct VolumeInfo {
     1336    char name[B_FILE_NAME_LENGTH];
     1337    char device[B_FILE_NAME_LENGTH];
     1338    char filesystem[B_OS_NAME_LENGTH];
     1339    off_t capacity;
     1340};
     1341
     1342
     1343class PartitionScorer : public KPartitionVisitor {
     1344public:
     1345    PartitionScorer(VolumeInfo& volumeInfo)
     1346        :
     1347        fBestPartition(NULL),
     1348        fBestScore(-1),
     1349        fVolumeInfo(volumeInfo)
     1350    {
     1351    }
     1352
     1353    virtual bool VisitPre(KPartition* partition)
     1354    {
     1355        if (!partition->ContainsFileSystem())
     1356            return false;
     1357
     1358        KPath path;
     1359        partition->GetPath(&path);
     1360
     1361        int score = 0;
     1362        if (strcmp(fVolumeInfo.name, partition->ContentName()) == 0)
     1363            score += 4;
     1364        if (strcmp(fVolumeInfo.device, path.Path()) == 0)
     1365            score += 3;
     1366        if (fVolumeInfo.capacity == partition->Size())
     1367            score += 2;
     1368        if (strcmp(fVolumeInfo.filesystem, partition->DiskSystem()
     1369            ->ShortName()) == 0)
     1370            score += 1;
     1371        if (score >= 4 && score > fBestScore) {
     1372            fBestPartition = partition;
     1373            fBestScore = score;
     1374        }
     1375
     1376        return false;
     1377    }
     1378
     1379    KPartition* fBestPartition;
     1380private:
     1381    int32       fBestScore;
     1382    VolumeInfo  fVolumeInfo;
     1383};
     1384
     1385
     1386status_t
     1387get_mount_point(KPartition* partition, KPath* mountPoint)
     1388{
     1389    if (!mountPoint || !partition->ContainsFileSystem())
     1390        return B_BAD_VALUE;
     1391
     1392    const char* volumeName = partition->ContentName();
     1393    if (!volumeName || strlen(volumeName) == 0)
     1394        volumeName = partition->Name();
     1395    if (!volumeName || strlen(volumeName) == 0)
     1396        volumeName = "unnamed volume";
     1397
     1398    char basePath[B_PATH_NAME_LENGTH];
     1399    int32 len = snprintf(basePath, sizeof(basePath), "/%s", volumeName);
     1400    for (int32 i = 1; i < len; i++)
     1401        if (basePath[i] == '/')
     1402            basePath[i] = '-';
     1403    char* path = mountPoint->LockBuffer();
     1404    int32 pathLen = mountPoint->BufferSize();
     1405    strncpy(path, basePath, pathLen);
     1406
     1407    struct stat dummy;
     1408    for (int i = 1; ; i++) {
     1409        if (stat(path, &dummy) != 0)
     1410            break;
     1411        snprintf(path, pathLen, "%s%d", basePath, i);
     1412    }
     1413
     1414    mountPoint->UnlockBuffer();
     1415    return B_OK;
     1416}
     1417
     1418
    13261419void
    13271420swap_init_post_modules()
    13281421{
     
    13311424    if (gReadOnlyBootDevice)
    13321425        return;
    13331426
    1334     off_t size = 0;
     1427    bool swapEnabled = true;
     1428    off_t swapSize = 0;
     1429    VolumeInfo selectedVolume = {};
    13351430
     1431    bool loadDefaults = true;
    13361432    void* settings = load_driver_settings("virtual_memory");
    13371433    if (settings != NULL) {
    1338         if (!get_driver_boolean_parameter(settings, "vm", false, false))
    1339             return;
     1434        const char* enabled = get_driver_parameter(settings, "vm",
     1435            NULL, NULL);
     1436        const char* size = get_driver_parameter(settings, "swap_size",
     1437            NULL, NULL);
     1438        const char* vol = get_driver_parameter(settings, "swap_volume_name",
     1439            NULL, NULL);
     1440        const char* dev = get_driver_parameter(settings, "swap_volume_device",
     1441            NULL, NULL);
     1442        const char* fs = get_driver_parameter(settings,
     1443            "swap_volume_filesystem", NULL, NULL);
     1444        const char* cap = get_driver_parameter(settings,
     1445            "swap_volume_capacity", NULL, NULL);
    13401446
    1341         const char* string = get_driver_parameter(settings, "swap_size", NULL,
    1342             NULL);
    1343         size = string ? atoll(string) : 0;
    1344 
     1447        if (enabled != NULL && size != NULL && dev != NULL
     1448            && vol != NULL && fs != NULL && cap != NULL) {
     1449            swapEnabled = get_driver_boolean_parameter(settings, "vm",
     1450                false, false);
     1451            swapSize = atoll(size);
     1452            strncpy(selectedVolume.name, vol, sizeof(selectedVolume.name));
     1453            strncpy(selectedVolume.device, dev,
     1454                sizeof(selectedVolume.device));
     1455            strncpy(selectedVolume.filesystem, fs,
     1456                sizeof(selectedVolume.filesystem));
     1457            selectedVolume.capacity = atoll(cap);
     1458            loadDefaults = false;
     1459        }
    13451460        unload_driver_settings(settings);
    1346     } else
    1347         size = (off_t)vm_page_num_pages() * B_PAGE_SIZE * 2;
     1461    }
    13481462
    1349     if (size < B_PAGE_SIZE)
     1463    if (loadDefaults) {
     1464        swapEnabled = true;
     1465        swapSize = (off_t)vm_page_num_pages() * B_PAGE_SIZE * 2;
     1466    }
     1467
     1468    if (!swapEnabled || swapSize < B_PAGE_SIZE)
    13501469        return;
    13511470
    1352     int fd = open("/var/swap", O_RDWR | O_CREAT | O_NOCACHE, S_IRUSR | S_IWUSR);
     1471    dev_t dev = -1;
     1472    if (!loadDefaults) {
     1473        KDiskDeviceManager::CreateDefault();
     1474        KDiskDeviceManager* manager = KDiskDeviceManager::Default();
     1475        PartitionScorer visitor(selectedVolume);
     1476
     1477        KDiskDevice* device;
     1478        int32 cookie = 0;
     1479        while ((device = manager->NextDevice(&cookie)) != NULL) {
     1480            if (device->IsReadOnlyMedia() || device->IsWriteOnce()
     1481                || device->IsRemovable())
     1482                continue;
     1483            device->VisitEachDescendant(&visitor);
     1484        }
     1485
     1486        const char* error = NULL;
     1487        if (!visitor.fBestPartition)
     1488            error = "nfnd";
     1489        else {
     1490            if (visitor.fBestPartition->IsMounted())
     1491                dev = visitor.fBestPartition->VolumeID();
     1492            else {
     1493                KPath devPath, mountPoint;
     1494                visitor.fBestPartition->GetPath(&devPath);
     1495                get_mount_point(visitor.fBestPartition, &mountPoint);
     1496                const char* mountPath = mountPoint.Path();
     1497                mkdir(mountPath, S_IRWXU | S_IRWXG | S_IRWXO);
     1498                dev = _kern_mount(mountPath, devPath.Path(),
     1499                    NULL, 0, NULL, 0);
     1500                if (dev < 0)
     1501                    error = "nmnt";
     1502            }
     1503        }
     1504        if (error != NULL) {
     1505            KPath path;
     1506            if (find_directory(B_COMMON_SETTINGS_DIRECTORY, gBootDevice,
     1507                false, path.LockBuffer(), path.BufferSize()) == B_OK) {
     1508                path.UnlockBuffer();
     1509                path.Append(kSwapErrorFilePath);
     1510                int errorFile = open(path.Path(), O_WRONLY | O_CREAT
     1511                    | O_TRUNC, S_IRUSR | S_IWUSR);
     1512                if (errorFile >= 0) {
     1513                    write(errorFile, error, strlen(error));
     1514                    close(errorFile);
     1515                }
     1516            }
     1517        }
     1518    }
     1519
     1520    if (dev < 0)
     1521        dev = gBootDevice;
     1522
     1523    KPath path;
     1524    struct fs_info info;
     1525    _kern_read_fs_info(dev, &info);
     1526    if (dev == gBootDevice)
     1527        path = kDefaultSwapPath;
     1528    else {
     1529        vfs_entry_ref_to_path(info.dev, info.root,
     1530            ".", path.LockBuffer(), path.BufferSize());
     1531        path.UnlockBuffer();
     1532        path.Append("swap");
     1533    }
     1534
     1535    const char* swapPath = path.Path();
     1536    off_t existingSwapSize = 0;
     1537    struct stat swapStat;
     1538    if (stat(swapPath, &swapStat) == 0)
     1539        existingSwapSize = swapStat.st_size;
     1540
     1541    off_t freeSpace = info.free_blocks * info.block_size + existingSwapSize;
     1542    off_t safeSpace = freeSpace - (off_t)(0.15 * freeSpace);
     1543    if (safeSpace < swapSize)
     1544        swapSize = safeSpace;
     1545
     1546    int fd = open(swapPath, O_RDWR | O_CREAT | O_NOCACHE, S_IRUSR |
     1547        S_IWUSR);
    13531548    if (fd < 0) {
    1354         dprintf("Can't open/create /var/swap: %s\n", strerror(errno));
     1549        dprintf("Can't open/create %s: %s\n", swapPath, strerror(errno));
    13551550        return;
    13561551    }
    13571552
    13581553    struct stat stat;
    1359     stat.st_size = size;
     1554    stat.st_size = swapSize;
    13601555    status_t error = _kern_write_stat(fd, NULL, false, &stat,
    13611556        sizeof(struct stat), B_STAT_SIZE | B_STAT_SIZE_INSECURE);
    1362     if (error != B_OK) {
    1363         dprintf("Failed to resize /var/swap to %lld bytes: %s\n", size,
    1364             strerror(error));
    1365     }
     1557    if (error != B_OK)
     1558        dprintf("Failed to resize %s to %lld bytes: %s\n", swapPath,
     1559            swapSize, strerror(error));
    13661560
    13671561    close(fd);
    13681562
    1369     error = swap_file_add("/var/swap");
     1563    error = swap_file_add(swapPath);
    13701564    if (error != B_OK)
    1371         dprintf("Failed to add swap file /var/swap: %s\n", strerror(error));
     1565        dprintf("Failed to add swap file %s: %s\n", swapPath,
     1566            strerror(error));
    13721567}
    13731568
    13741569
  • src/system/kernel/vm/Jamfile

     
    11SubDir HAIKU_TOP src system kernel vm ;
    22
    33UsePrivateHeaders shared ;
     4UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
     5UsePrivateHeaders [ FDirName kernel util ] ;
    46
    57UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) device_manager ] ;
    68