Commit 67f715ec authored by Nicholas Verne's avatar Nicholas Verne Committed by Commit Bot

Crostini no longer fails to start when disk space is low.

The previous container restart flow would return an error if there was
insufficient disk. Free disk size is not relevant if there's an existing disk
image.

Bug: 891165
Change-Id: I34ed750263182e920ab96befc8b00f1f2b2db89e
Reviewed-on: https://chromium-review.googlesource.com/c/1328482Reviewed-by: default avatarBen Wells <benwells@chromium.org>
Commit-Queue: Nicholas Verne <nverne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#607490}
parent 5f90142c
...@@ -185,9 +185,49 @@ class CrostiniManager::CrostiniRestarter ...@@ -185,9 +185,49 @@ class CrostiniManager::CrostiniRestarter
FinishRestart(result); FinishRestart(result);
return; return;
} }
crostini_manager_->ListVmDisks(
base::BindOnce(&CrostiniRestarter::ListVmDisksFinished, this));
}
void ListVmDisksFinished(CrostiniResult result, int64_t disk_space_taken) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (is_aborted_)
return;
if (result != CrostiniResult::SUCCESS) {
LOG(ERROR) << "Failed to list disk images.";
FinishRestart(result);
return;
}
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&base::SysInfo::AmountOfFreeDiskSpace,
base::FilePath(kHomeDirectory)),
base::BindOnce(&CrostiniRestarter::CreateDiskImageAfterSizeCheck, this,
disk_space_taken));
}
void CreateDiskImageAfterSizeCheck(int64_t disk_space_taken,
int64_t free_disk_bytes) {
int64_t disk_size_available = (free_disk_bytes * 9) / 10;
// If there's no existing disk image, need enough space to create one.
if (disk_space_taken == 0) {
// Don't enforce minimum disk size on dev box or trybots because
// base::SysInfo::AmountOfFreeDiskSpace returns zero in testing.
if (disk_size_available < kMinimumDiskSize &&
base::SysInfo::IsRunningOnChromeOS()) {
LOG(ERROR) << "Insufficient disk available. Need to free "
<< kMinimumDiskSize - disk_size_available << " bytes";
FinishRestart(CrostiniResult::INSUFFICIENT_DISK);
return;
}
}
// If we have an already existing disk, CreateDiskImage will just return its
// path so we can pass it to StartTerminaVm.
crostini_manager_->CreateDiskImage( crostini_manager_->CreateDiskImage(
base::FilePath(vm_name_), base::FilePath(vm_name_),
vm_tools::concierge::StorageLocation::STORAGE_CRYPTOHOME_ROOT, vm_tools::concierge::StorageLocation::STORAGE_CRYPTOHOME_ROOT,
disk_size_available,
base::BindOnce(&CrostiniRestarter::CreateDiskImageFinished, this)); base::BindOnce(&CrostiniRestarter::CreateDiskImageFinished, this));
} }
...@@ -659,6 +699,7 @@ void CrostiniManager::OnStopConcierge(StopConciergeCallback callback, ...@@ -659,6 +699,7 @@ void CrostiniManager::OnStopConcierge(StopConciergeCallback callback,
void CrostiniManager::CreateDiskImage( void CrostiniManager::CreateDiskImage(
const base::FilePath& disk_path, const base::FilePath& disk_path,
vm_tools::concierge::StorageLocation storage_location, vm_tools::concierge::StorageLocation storage_location,
int64_t disk_size_bytes,
CreateDiskImageCallback callback) { CreateDiskImageCallback callback) {
std::string disk_path_string = disk_path.AsUTF8Unsafe(); std::string disk_path_string = disk_path.AsUTF8Unsafe();
if (disk_path_string.empty()) { if (disk_path_string.empty()) {
...@@ -687,34 +728,8 @@ void CrostiniManager::CreateDiskImage( ...@@ -687,34 +728,8 @@ void CrostiniManager::CreateDiskImage(
return; return;
} }
request.set_storage_location(storage_location); request.set_storage_location(storage_location);
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&base::SysInfo::AmountOfFreeDiskSpace,
base::FilePath(kHomeDirectory)),
base::BindOnce(&CrostiniManager::CreateDiskImageAfterSizeCheck,
weak_ptr_factory_.GetWeakPtr(), std::move(request),
std::move(callback)));
}
void CrostiniManager::CreateDiskImageAfterSizeCheck(
vm_tools::concierge::CreateDiskImageRequest request,
CreateDiskImageCallback callback,
int64_t free_disk_size) {
int64_t disk_size = (free_disk_size * 9) / 10;
// Skip disk size check on dev box or trybots because
// base::SysInfo::AmountOfFreeDiskSpace returns zero in testing.
if (disk_size < kMinimumDiskSize && base::SysInfo::IsRunningOnChromeOS()) {
LOG(ERROR) << "Insufficient disk available. Need to free "
<< kMinimumDiskSize - disk_size << " bytes";
std::move(callback).Run(
CrostiniResult::CLIENT_ERROR,
vm_tools::concierge::DiskImageStatus::DISK_STATUS_UNKNOWN,
base::FilePath());
return;
}
// The logical size of the new disk image, in bytes. // The logical size of the new disk image, in bytes.
request.set_disk_size(std::move(disk_size)); request.set_disk_size(std::move(disk_size_bytes));
GetConciergeClient()->CreateDiskImage( GetConciergeClient()->CreateDiskImage(
std::move(request), std::move(request),
......
...@@ -33,6 +33,7 @@ enum class CrostiniResult { ...@@ -33,6 +33,7 @@ enum class CrostiniResult {
SUCCESS, SUCCESS,
DBUS_ERROR, DBUS_ERROR,
UNPARSEABLE_RESPONSE, UNPARSEABLE_RESPONSE,
INSUFFICIENT_DISK,
CREATE_DISK_IMAGE_FAILED, CREATE_DISK_IMAGE_FAILED,
VM_START_FAILED, VM_START_FAILED,
VM_STOP_FAILED, VM_STOP_FAILED,
...@@ -234,6 +235,8 @@ class CrostiniManager : public KeyedService, ...@@ -234,6 +235,8 @@ class CrostiniManager : public KeyedService,
const base::FilePath& disk_path, const base::FilePath& disk_path,
// The storage location for the disk image // The storage location for the disk image
vm_tools::concierge::StorageLocation storage_location, vm_tools::concierge::StorageLocation storage_location,
// The logical size of the disk image, in bytes
int64_t disk_size_bytes,
CreateDiskImageCallback callback); CreateDiskImageCallback callback);
// Checks the arguments for destroying a named Termina VM disk image. // Checks the arguments for destroying a named Termina VM disk image.
...@@ -541,12 +544,6 @@ class CrostiniManager : public KeyedService, ...@@ -541,12 +544,6 @@ class CrostiniManager : public KeyedService,
// checking component registration code may block. // checking component registration code may block.
void MaybeUpgradeCrostiniAfterChecks(); void MaybeUpgradeCrostiniAfterChecks();
// Helper for CrostiniManager::CreateDiskImage. Separated so it can be run
// off the main thread.
void CreateDiskImageAfterSizeCheck(
vm_tools::concierge::CreateDiskImageRequest request,
CreateDiskImageCallback callback,
int64_t free_disk_size);
void FinishRestart(CrostiniRestarter* restarter, CrostiniResult result); void FinishRestart(CrostiniRestarter* restarter, CrostiniResult result);
......
...@@ -24,6 +24,7 @@ namespace crostini { ...@@ -24,6 +24,7 @@ namespace crostini {
namespace { namespace {
const char kVmName[] = "vm_name"; const char kVmName[] = "vm_name";
const char kContainerName[] = "container_name"; const char kContainerName[] = "container_name";
constexpr int64_t kDiskSizeBytes = 4ll * 1024 * 1024 * 1024; // 4 GiB
} // namespace } // namespace
class CrostiniManagerTest : public testing::Test { class CrostiniManagerTest : public testing::Test {
...@@ -177,7 +178,7 @@ TEST_F(CrostiniManagerTest, CreateDiskImageNameError) { ...@@ -177,7 +178,7 @@ TEST_F(CrostiniManagerTest, CreateDiskImageNameError) {
const base::FilePath& disk_path = base::FilePath(""); const base::FilePath& disk_path = base::FilePath("");
crostini_manager()->CreateDiskImage( crostini_manager()->CreateDiskImage(
disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT, disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_ROOT, kDiskSizeBytes,
base::BindOnce(&CrostiniManagerTest::CreateDiskImageClientErrorCallback, base::BindOnce(&CrostiniManagerTest::CreateDiskImageClientErrorCallback,
base::Unretained(this), run_loop()->QuitClosure())); base::Unretained(this), run_loop()->QuitClosure()));
run_loop()->Run(); run_loop()->Run();
...@@ -189,6 +190,7 @@ TEST_F(CrostiniManagerTest, CreateDiskImageStorageLocationError) { ...@@ -189,6 +190,7 @@ TEST_F(CrostiniManagerTest, CreateDiskImageStorageLocationError) {
crostini_manager()->CreateDiskImage( crostini_manager()->CreateDiskImage(
disk_path, disk_path,
vm_tools::concierge::StorageLocation_INT_MIN_SENTINEL_DO_NOT_USE_, vm_tools::concierge::StorageLocation_INT_MIN_SENTINEL_DO_NOT_USE_,
kDiskSizeBytes,
base::BindOnce(&CrostiniManagerTest::CreateDiskImageClientErrorCallback, base::BindOnce(&CrostiniManagerTest::CreateDiskImageClientErrorCallback,
base::Unretained(this), run_loop()->QuitClosure())); base::Unretained(this), run_loop()->QuitClosure()));
run_loop()->Run(); run_loop()->Run();
...@@ -199,6 +201,7 @@ TEST_F(CrostiniManagerTest, CreateDiskImageSuccess) { ...@@ -199,6 +201,7 @@ TEST_F(CrostiniManagerTest, CreateDiskImageSuccess) {
crostini_manager()->CreateDiskImage( crostini_manager()->CreateDiskImage(
disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_DOWNLOADS, disk_path, vm_tools::concierge::STORAGE_CRYPTOHOME_DOWNLOADS,
kDiskSizeBytes,
base::BindOnce(&CrostiniManagerTest::CreateDiskImageSuccessCallback, base::BindOnce(&CrostiniManagerTest::CreateDiskImageSuccessCallback,
base::Unretained(this), run_loop()->QuitClosure())); base::Unretained(this), run_loop()->QuitClosure()));
run_loop()->Run(); run_loop()->Run();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment