Ticket #7742: swap-kernel-v1.diff

File swap-kernel-v1.diff, 9.4 KB (added by kallisti5, 12 years ago)
  • src/system/kernel/vm/Jamfile

    diff --git a/src/system/kernel/vm/Jamfile b/src/system/kernel/vm/Jamfile
    index fa0282d..a646e71 100644
    a b SubDir HAIKU_TOP src system kernel vm ;  
    33UsePrivateHeaders shared ;
    44
    55UseHeaders [ FDirName $(SUBDIR) $(DOTDOT) device_manager ] ;
     6UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
     7UsePrivateHeaders [ FDirName kernel util ] ;
    68
    79KernelMergeObject kernel_vm.o :
    810    PageCacheLocker.cpp
  • src/system/kernel/vm/VMAnonymousCache.cpp

    diff --git a/src/system/kernel/vm/VMAnonymousCache.cpp b/src/system/kernel/vm/VMAnonymousCache.cpp
    index eae0b54..cbd0126 100644
    a b  
    11/*
     2 * Copyright 2012, Alexander von Gluck IV, kallisti5@unixzen.com.
     3 * Copyright 2011, Hamish Morrison, hamish@lavabit.com.
    24 * Copyright 2008, Zhao Shuai, upczhsh@163.com.
    35 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
    46 * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
     
    1719#include <string.h>
    1820#include <unistd.h>
    1921
     22#include <FindDirectory.h>
    2023#include <KernelExport.h>
    2124#include <NodeMonitor.h>
    2225
    2326#include <arch_config.h>
    2427#include <boot_device.h>
     28#include <disk_device_manager/KDiskDevice.h>
     29#include <disk_device_manager/KDiskDeviceManager.h>
     30#include <disk_device_manager/KDiskSystem.h>
     31#include <disk_device_manager/KPartitionVisitor.h>
    2532#include <driver_settings.h>
    2633#include <fs/fd.h>
     34#include <fs/KPath.h>
     35#include <fs_info.h>
    2736#include <fs_interface.h>
    2837#include <heap.h>
    2938#include <kernel_daemon.h>
     
    6978#define SWAP_BLOCK_MASK  (SWAP_BLOCK_PAGES - 1)
    7079
    7180
     81static const char* const kDefaultSwapPath = "/var/swap";
     82
    7283struct swap_file : DoublyLinkedListLinkImpl<swap_file> {
    7384    int             fd;
    7485    struct vnode*   vnode;
    VMAnonymousCache::_MergeSwapPages(VMAnonymousCache* source)  
    11671178// #pragma mark -
    11681179
    11691180
     1181struct VolumeInfo {
     1182    char name[B_FILE_NAME_LENGTH];
     1183    char device[B_FILE_NAME_LENGTH];
     1184    char filesystem[B_OS_NAME_LENGTH];
     1185    off_t capacity;
     1186};
     1187
     1188
     1189class PartitionScorer : public KPartitionVisitor {
     1190public:
     1191    PartitionScorer(VolumeInfo& volumeInfo)
     1192        :
     1193        fBestPartition(NULL),
     1194        fBestScore(-1),
     1195        fVolumeInfo(volumeInfo)
     1196    {
     1197    }
     1198
     1199    virtual bool VisitPre(KPartition* partition)
     1200    {
     1201        if (!partition->ContainsFileSystem())
     1202            return false;
     1203
     1204        KPath path;
     1205        partition->GetPath(&path);
     1206
     1207        int score = 0;
     1208        if (strcmp(fVolumeInfo.name, partition->ContentName()) == 0)
     1209            score += 4;
     1210        if (strcmp(fVolumeInfo.device, path.Path()) == 0)
     1211            score += 3;
     1212        if (fVolumeInfo.capacity == partition->Size())
     1213            score += 2;
     1214        if (strcmp(fVolumeInfo.filesystem,
     1215            partition->DiskSystem()->ShortName()) == 0) {
     1216            score += 1;
     1217        }
     1218        if (score >= 4 && score > fBestScore) {
     1219            fBestPartition = partition;
     1220            fBestScore = score;
     1221        }
     1222
     1223        return false;
     1224    }
     1225
     1226    KPartition* fBestPartition;
     1227
     1228private:
     1229    int32       fBestScore;
     1230    VolumeInfo  fVolumeInfo;
     1231};
     1232
     1233
     1234status_t
     1235get_mount_point(KPartition* partition, KPath* mountPoint)
     1236{
     1237    if (!mountPoint || !partition->ContainsFileSystem())
     1238        return B_BAD_VALUE;
     1239
     1240    const char* volumeName = partition->ContentName();
     1241    if (!volumeName || strlen(volumeName) == 0)
     1242        volumeName = partition->Name();
     1243    if (!volumeName || strlen(volumeName) == 0)
     1244        volumeName = "unnamed volume";
     1245
     1246    char basePath[B_PATH_NAME_LENGTH];
     1247    int32 len = snprintf(basePath, sizeof(basePath), "/%s", volumeName);
     1248    for (int32 i = 1; i < len; i++)
     1249        if (basePath[i] == '/')
     1250        basePath[i] = '-';
     1251    char* path = mountPoint->LockBuffer();
     1252    int32 pathLen = mountPoint->BufferSize();
     1253    strncpy(path, basePath, pathLen);
     1254
     1255    struct stat dummy;
     1256    for (int i = 1; ; i++) {
     1257        if (stat(path, &dummy) != 0)
     1258            break;
     1259        snprintf(path, pathLen, "%s%d", basePath, i);
     1260    }
     1261
     1262    mountPoint->UnlockBuffer();
     1263    return B_OK;
     1264}
     1265
     1266
    11701267status_t
    11711268swap_file_add(const char* path)
    11721269{
    swap_init_post_modules()  
    13401437    if (gReadOnlyBootDevice)
    13411438        return;
    13421439
    1343     off_t size = 0;
     1440    bool swapEnabled = true;
     1441    bool swapAutomatic = true;
     1442    off_t swapSize = 0;
     1443    VolumeInfo selectedVolume = {};
    13441444
    13451445    void* settings = load_driver_settings("virtual_memory");
     1446
    13461447    if (settings != NULL) {
    1347         if (!get_driver_boolean_parameter(settings, "vm", false, false)) {
    1348             unload_driver_settings(settings);
    1349             return;
     1448        // We pass a lot of information on the swap device, this is mostly to
     1449        // ensure that we are dealing with the same device that was configured.
     1450
     1451        // TODO: Some kind of BFS uuid would be great here :)
     1452        const char* enabled = get_driver_parameter(settings, "vm", NULL, NULL);
     1453
     1454        if (enabled != NULL) {
     1455            swapEnabled = get_driver_boolean_parameter(settings, "vm",
     1456                false, false);
     1457
     1458            const char* size = get_driver_parameter(settings, "swap_size",
     1459                NULL, NULL);
     1460            const char* volume = get_driver_parameter(settings,
     1461                "swap_volume_name", NULL, NULL);
     1462            const char* device = get_driver_parameter(settings,
     1463                "swap_volume_device", NULL, NULL);
     1464            const char* filesystem = get_driver_parameter(settings,
     1465                "swap_volume_filesystem", NULL, NULL);
     1466            const char* capacity = get_driver_parameter(settings,
     1467                "swap_volume_capacity", NULL, NULL);
     1468
     1469            if (size != NULL && device != NULL && volume != NULL
     1470                && filesystem != NULL && capacity != NULL) {
     1471                // User specified a size / volume
     1472                swapAutomatic = false;
     1473                swapSize = atoll(size);
     1474                strncpy(selectedVolume.name, volume,
     1475                    sizeof(selectedVolume.name));
     1476                strncpy(selectedVolume.device, device,
     1477                    sizeof(selectedVolume.device));
     1478                strncpy(selectedVolume.filesystem, filesystem,
     1479                    sizeof(selectedVolume.filesystem));
     1480                selectedVolume.capacity = atoll(capacity);
     1481            }
    13501482        }
     1483        unload_driver_settings(settings);
     1484    }
    13511485
    1352         const char* string = get_driver_parameter(settings, "swap_size", NULL,
    1353             NULL);
    1354         size = string ? atoll(string) : 0;
     1486    if (swapAutomatic) {
     1487        swapEnabled = true;
     1488        swapSize = (off_t)vm_page_num_pages() * B_PAGE_SIZE * 2;
     1489    }
    13551490
    1356         unload_driver_settings(settings);
     1491    if (!swapEnabled || swapSize < B_PAGE_SIZE)
     1492        return;
     1493
     1494    dev_t dev = -1;
     1495
     1496    if (!swapAutomatic) {
     1497        KDiskDeviceManager::CreateDefault();
     1498        KDiskDeviceManager* manager = KDiskDeviceManager::Default();
     1499        PartitionScorer visitor(selectedVolume);
     1500
     1501        KDiskDevice* device;
     1502        int32 cookie = 0;
     1503        while ((device = manager->NextDevice(&cookie)) != NULL) {
     1504            if (device->IsReadOnlyMedia() || device->IsWriteOnce()
     1505                || device->IsRemovable()) {
     1506                continue;
     1507            }
     1508            device->VisitEachDescendant(&visitor);
     1509        }
     1510
     1511        if (!visitor.fBestPartition) {
     1512            dprintf("%s: Can't find configured swap partition '%s'\n",
     1513                __func__, selectedVolume.name);
     1514        } else {
     1515            if (visitor.fBestPartition->IsMounted())
     1516                dev = visitor.fBestPartition->VolumeID();
     1517            else {
     1518                KPath devPath, mountPoint;
     1519                visitor.fBestPartition->GetPath(&devPath);
     1520                get_mount_point(visitor.fBestPartition, &mountPoint);
     1521                const char* mountPath = mountPoint.Path();
     1522                mkdir(mountPath, S_IRWXU | S_IRWXG | S_IRWXO);
     1523                dev = _kern_mount(mountPath, devPath.Path(),
     1524                    NULL, 0, NULL, 0);
     1525                if (dev < 0) {
     1526                    dprintf("%s: Can't mount configured swap partition '%s'\n",
     1527                        __func__, selectedVolume.name);
     1528                }
     1529            }
     1530        }
     1531    }
     1532
     1533    if (dev < 0)
     1534        dev = gBootDevice;
     1535
     1536    KPath path;
     1537    struct fs_info info;
     1538    _kern_read_fs_info(dev, &info);
     1539    if (dev == gBootDevice)
     1540        path = kDefaultSwapPath;
     1541    else {
     1542        vfs_entry_ref_to_path(info.dev, info.root,
     1543            ".", path.LockBuffer(), path.BufferSize());
     1544        path.UnlockBuffer();
     1545        path.Append("swap");
     1546    }
     1547
     1548    const char* swapPath = path.Path();
     1549
     1550    // Swap size limits prevent oversized swap files
     1551    off_t existingSwapSize = 0;
     1552    struct stat existingSwapStat;
     1553    if (stat(swapPath, &existingSwapStat) == 0)
     1554        existingSwapSize = existingSwapStat.st_size;
     1555
     1556    off_t freeSpace = info.free_blocks * info.block_size + existingSwapSize;
     1557    off_t maxSwap = freeSpace;
     1558    if (swapAutomatic) {
     1559        // Adjust automatic swap to a maximum of 25% of the free space
     1560        maxSwap = (off_t)(0.25 * freeSpace);
    13571561    } else {
    1358         size = (off_t)vm_page_num_pages() * B_PAGE_SIZE * 2;
     1562        // If user specified, leave 10% of the disk free
     1563        maxSwap = freeSpace - (off_t)(0.10 * freeSpace);
     1564        dprintf("%s: Warning: User specified swap file consumes over 90%% of "
     1565            "the available free space, limiting to 90%%\n", __func__);
    13591566    }
    13601567
    1361     if (size < B_PAGE_SIZE)
    1362         return;
     1568    if (swapSize > maxSwap)
     1569        swapSize = maxSwap;
    13631570
    1364     int fd = open("/var/swap", O_RDWR | O_CREAT | O_NOCACHE, S_IRUSR | S_IWUSR);
     1571    // Create swap file
     1572    int fd = open(swapPath, O_RDWR | O_CREAT | O_NOCACHE, S_IRUSR | S_IWUSR);
    13651573    if (fd < 0) {
    1366         dprintf("Can't open/create /var/swap: %s\n", strerror(errno));
     1574        dprintf("%s: Can't open/create %s: %s\n", __func__,
     1575            swapPath, strerror(errno));
    13671576        return;
    13681577    }
    13691578
    13701579    struct stat stat;
    1371     stat.st_size = size;
     1580    stat.st_size = swapSize;
    13721581    status_t error = _kern_write_stat(fd, NULL, false, &stat,
    13731582        sizeof(struct stat), B_STAT_SIZE | B_STAT_SIZE_INSECURE);
    13741583    if (error != B_OK) {
    1375         dprintf("Failed to resize /var/swap to %lld bytes: %s\n", size,
    1376             strerror(error));
     1584        dprintf("%s: Failed to resize %s to %lld bytes: %s\n", __func__,
     1585            swapPath, swapSize, strerror(error));
    13771586    }
    13781587
    13791588    close(fd);
    13801589
    1381     error = swap_file_add("/var/swap");
    1382     if (error != B_OK)
    1383         dprintf("Failed to add swap file /var/swap: %s\n", strerror(error));
     1590    error = swap_file_add(swapPath);
     1591    if (error != B_OK) {
     1592        dprintf("%s: Failed to add swap file %s: %s\n", __func__, swapPath,
     1593            strerror(error));
     1594    }
    13841595}
    13851596
    13861597