blob: aea989d6c0cddc64a02b22627eb6e764534ab62f [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/dispatcher.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace-provider/provider.h>
#include "f2fs.h"
namespace f2fs {
// TODO: change .configurable to true once the feature is supported
// TODO: set default on for inline_dentry after inline dentry check on fsck is available
const MountOpt default_option[] = {
{"background_gc_off", 1, false},
#ifdef F2FS_ROLL_FORWARD
{"disable_roll_forward", 0, false},
#else
{"disable_roll_forward", 1, false},
#endif
{"discard", 1, true},
{"no_heap", 1, false},
{"nouser_xattr", 1, false},
{"noacl", 1, false},
{"disable_ext_identify", 0, true},
{"inline_xattr", 0, false},
{"inline_data", 0, false},
{"inline_dentry", 0, true},
{"active_logs", 6, true},
};
zx_status_t Mount(const MountOptions &options, std::unique_ptr<f2fs::Bcache> bc) {
zx::channel outgoing_server = zx::channel(zx_take_startup_handle(PA_DIRECTORY_REQUEST));
zx::channel root_server = zx::channel(zx_take_startup_handle(FS_HANDLE_ROOT_ID));
if (outgoing_server.is_valid() && root_server.is_valid()) {
FX_LOGS(ERROR) << "both PA_DIRECTORY_REQUEST and FS_HANDLE_ROOT_ID provided - need one or the "
"other.";
return ZX_ERR_BAD_STATE;
}
zx::channel export_root;
f2fs::ServeLayout serve_layout;
if (outgoing_server.is_valid()) {
export_root = std::move(outgoing_server);
serve_layout = f2fs::ServeLayout::kExportDirectory;
} else if (root_server.is_valid()) {
export_root = std::move(root_server);
serve_layout = f2fs::ServeLayout::kDataRootOnly;
} else {
FX_LOGS(ERROR) << "could not get startup handle to serve on";
return ZX_ERR_BAD_STATE;
}
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
trace::TraceProviderWithFdio trace_provider(loop.dispatcher());
auto on_unmount = [&loop]() {
loop.Quit();
FX_LOGS(WARNING) << "Unmounted";
};
auto fs_or = CreateFsAndRoot(options, loop.dispatcher(), std::move(bc), std::move(export_root),
std::move(on_unmount), serve_layout);
if (fs_or.is_error()) {
FX_LOGS(ERROR) << "failed to create filesystem object " << fs_or.status_string();
return EXIT_FAILURE;
}
FX_LOGS(INFO) << "Mounted successfully";
ZX_ASSERT(loop.Run() == ZX_ERR_CANCELED);
return ZX_OK;
}
MountOptions::MountOptions() {
for (uint32_t i = 0; i < kOptMaxNum; i++) {
opt_[i] = default_option[i];
}
}
zx_status_t MountOptions::GetValue(const uint32_t opt_id, uint32_t *out) {
if (opt_id >= kOptMaxNum)
return ZX_ERR_INVALID_ARGS;
*out = opt_[opt_id].value;
return ZX_OK;
}
uint32_t MountOptions::GetOptionID(const std::string_view &opt) {
uint32_t i;
for (i = 0; i < kOptMaxNum; i++) {
if (opt_[i].name.compare(opt) == 0) {
break;
}
}
return i;
}
zx_status_t MountOptions::SetValue(const std::string_view &opt, const uint32_t value) {
zx_status_t ret = ZX_ERR_INVALID_ARGS;
uint32_t id = GetOptionID(opt);
if (id < kOptMaxNum && !opt_[id].configurable) {
FX_LOGS(WARNING) << opt << " is not configurable.";
} else {
switch (id) {
case kOptActiveLogs:
if (value != 2 && value != 4 && value != 6) {
FX_LOGS(WARNING) << opt << " can be set only to 2, 4, or 6.";
} else {
opt_[id].value = value;
ret = ZX_OK;
}
break;
case kOptDiscard:
case kOptBgGcOff:
case kOptNoHeap:
case kOptDisableExtIdentify:
case kOptNoUserXAttr:
case kOptNoAcl:
case kOptDisableRollForward:
case kOptInlineXattr:
case kOptInlineData:
case kOptInlineDentry:
opt_[id].value = value;
ret = ZX_OK;
break;
default:
FX_LOGS(WARNING) << opt << " is not supported.";
break;
};
}
return ret;
}
} // namespace f2fs