| 1335 | struct 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 | |
| 1343 | class PartitionScorer : public KPartitionVisitor { |
| 1344 | public: |
| 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; |
| 1380 | private: |
| 1381 | int32 fBestScore; |
| 1382 | VolumeInfo fVolumeInfo; |
| 1383 | }; |
| 1384 | |
| 1385 | |
| 1386 | status_t |
| 1387 | get_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 | |
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); |
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 | } |
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); |