diff --git a/fs/util.cc b/fs/util.cc new file mode 100644 index 00000000..71b5aecb --- /dev/null +++ b/fs/util.cc @@ -0,0 +1,153 @@ + +#include "util.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "fs_zenfs.h" + +namespace ROCKSDB_NAMESPACE { + +std::unique_ptr zbd_open(std::string const &zbd_path, + bool readonly, bool exclusive) { + std::unique_ptr zbd{ + new ZonedBlockDevice(zbd_path, nullptr)}; + IOStatus open_status = zbd->Open(readonly, exclusive); + + if (!open_status.ok()) { + fprintf(stderr, "Failed to open zoned block device: %s, error: %s\n", + zbd_path.c_str(), open_status.ToString().c_str()); + zbd.reset(); + } + + return zbd; +} + +// Here we pass 'zbd' by non-const reference to be able to pass its ownership +// to 'zenFS' +Status zenfs_mount(std::unique_ptr &zbd, + std::unique_ptr *zenFS, bool readonly) { + Status s; + + std::unique_ptr localZenFS{ + new ZenFS(zbd.release(), FileSystem::Default(), nullptr)}; + s = localZenFS->Mount(readonly); + if (!s.ok()) { + localZenFS.reset(); + } + *zenFS = std::move(localZenFS); + + return s; +} + +static int is_dir(const char *path) { + struct stat st; + if (stat(path, &st) != 0) { + fprintf(stderr, "Failed to stat %s\n", path); + return 1; + } + return S_ISDIR(st.st_mode); +} + +// Create or check pre-existing aux directory and fail if it is +// inaccessible by current user and if it has previous data +static int create_aux_dir(const char *path) { + struct dirent *dent; + size_t nfiles = 0; + int ret = 0; + + errno = 0; + ret = mkdir(path, 0750); + if (ret < 0 && EEXIST != errno) { + fprintf(stderr, "Failed to create aux directory %s: %s\n", path, + strerror(errno)); + return 1; + } + // The aux_path is now available, check if it is a directory infact + // and is empty and the user has access permission + + if (!is_dir(path)) { + fprintf(stderr, "Aux path %s is not a directory\n", path); + return 1; + } + + errno = 0; + + auto closedirDeleter = [](DIR *d) { + if (d != nullptr) closedir(d); + }; + std::unique_ptr aux_dir{ + opendir(path), std::move(closedirDeleter)}; + if (errno) { + fprintf(stderr, "Failed to open aux directory %s: %s\n", path, + strerror(errno)); + return 1; + } + + // Consider the directory as non-empty if any files/dir other + // than . and .. are found. + while ((dent = readdir(aux_dir.get())) != NULL && nfiles <= 2) ++nfiles; + if (nfiles > 2) { + fprintf(stderr, "Aux directory %s is not empty.\n", path); + return 1; + } + + if (access(path, R_OK | W_OK | X_OK) < 0) { + fprintf(stderr, + "User does not have access permissions on " + "aux directory %s\n", + path); + return 1; + } + + return 0; +} + +int zenfs_mkfs(std::string const &zbd_path, std::string const &aux_path, + int finish_threshold, bool force) { + Status s; + + if (create_aux_dir(aux_path.c_str())) return 1; + + std::unique_ptr zbd = zbd_open(zbd_path, false, true); + if (!zbd) return 1; + + std::unique_ptr zenFS; + s = zenfs_mount(zbd, &zenFS, false); + if ((s.ok() || !s.IsNotFound()) && !force) { + fprintf( + stderr, + "Existing filesystem found, use --force if you want to replace it.\n"); + return 1; + } + + zenFS.reset(); + + zbd = zbd_open(zbd_path, false, true); + ZonedBlockDevice *zbdRaw = zbd.get(); + zenFS.reset(new ZenFS(zbd.release(), FileSystem::Default(), nullptr)); + + std::string aux_path_patched = aux_path; + if (aux_path_patched.back() != '/') aux_path_patched.append("/"); + + s = zenFS->MkFS(aux_path_patched, finish_threshold); + if (!s.ok()) { + fprintf(stderr, "Failed to create file system, error: %s\n", + s.ToString().c_str()); + return 1; + } + + fprintf(stdout, "ZenFS file system created. Free space: %lu MB\n", + zbdRaw->GetFreeSpace() / (1024 * 1024)); + + return 0; +} +} // namespace ROCKSDB_NAMESPACE diff --git a/fs/util.h b/fs/util.h new file mode 100644 index 00000000..a59378b5 --- /dev/null +++ b/fs/util.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "fs_zenfs.h" +#include "rocksdb/status.h" + +namespace ROCKSDB_NAMESPACE { + +std::unique_ptr zbd_open(std::string const& zbd_path, + bool readonly, bool exclusive); + +Status zenfs_mount(std::unique_ptr& zbd, + std::unique_ptr* zenFS, bool readonly); + +int zenfs_mkfs(std::string const& zbd_path, std::string const& aux_path, + int finish_threshold, bool force); +} // namespace ROCKSDB_NAMESPACE diff --git a/util/zenfs.cc b/util/zenfs.cc index c864b509..91eadd30 100644 --- a/util/zenfs.cc +++ b/util/zenfs.cc @@ -20,9 +20,11 @@ #ifdef WITH_TERARKDB #include +#include #include #else #include +#include #include #endif @@ -53,100 +55,6 @@ void AddDirSeparatorAtEnd(std::string &path) { if (path.back() != '/') path = path + "/"; } -std::unique_ptr zbd_open(bool readonly, bool exclusive) { - std::unique_ptr zbd{ - new ZonedBlockDevice(FLAGS_zbd, nullptr)}; - IOStatus open_status = zbd->Open(readonly, exclusive); - - if (!open_status.ok()) { - fprintf(stderr, "Failed to open zoned block device: %s, error: %s\n", - FLAGS_zbd.c_str(), open_status.ToString().c_str()); - zbd.reset(); - } - - return zbd; -} - -// Here we pass 'zbd' by non-const reference to be able to pass its ownership -// to 'zenFS' -Status zenfs_mount(std::unique_ptr &zbd, - std::unique_ptr *zenFS, bool readonly) { - Status s; - - std::unique_ptr localZenFS{ - new ZenFS(zbd.release(), FileSystem::Default(), nullptr)}; - s = localZenFS->Mount(readonly); - if (!s.ok()) { - localZenFS.reset(); - } - *zenFS = std::move(localZenFS); - - return s; -} - -int is_dir(const char *path) { - struct stat st; - if (stat(path, &st) != 0) { - fprintf(stderr, "Failed to stat %s\n", path); - return 1; - } - return S_ISDIR(st.st_mode); -} - -// Create or check pre-existing aux directory and fail if it is -// inaccessible by current user and if it has previous data -int create_aux_dir(const char *path) { - struct dirent *dent; - size_t nfiles = 0; - int ret = 0; - - errno = 0; - ret = mkdir(path, 0750); - if (ret < 0 && EEXIST != errno) { - fprintf(stderr, "Failed to create aux directory %s: %s\n", path, - strerror(errno)); - return 1; - } - // The aux_path is now available, check if it is a directory infact - // and is empty and the user has access permission - - if (!is_dir(path)) { - fprintf(stderr, "Aux path %s is not a directory\n", path); - return 1; - } - - errno = 0; - - auto closedirDeleter = [](DIR *d) { - if (d != nullptr) closedir(d); - }; - std::unique_ptr aux_dir{ - opendir(path), std::move(closedirDeleter)}; - if (errno) { - fprintf(stderr, "Failed to open aux directory %s: %s\n", path, - strerror(errno)); - return 1; - } - - // Consider the directory as non-empty if any files/dir other - // than . and .. are found. - while ((dent = readdir(aux_dir.get())) != NULL && nfiles <= 2) ++nfiles; - if (nfiles > 2) { - fprintf(stderr, "Aux directory %s is not empty.\n", path); - return 1; - } - - if (access(path, R_OK | W_OK | X_OK) < 0) { - fprintf(stderr, - "User does not have access permissions on " - "aux directory %s\n", - path); - return 1; - } - - return 0; -} - int zenfs_tool_mkfs() { Status s; @@ -155,39 +63,9 @@ int zenfs_tool_mkfs() { return 1; } - if (create_aux_dir(FLAGS_aux_path.c_str())) return 1; - - std::unique_ptr zbd = zbd_open(false, true); - if (!zbd) return 1; - - std::unique_ptr zenFS; - s = zenfs_mount(zbd, &zenFS, false); - if ((s.ok() || !s.IsNotFound()) && !FLAGS_force) { - fprintf( - stderr, - "Existing filesystem found, use --force if you want to replace it.\n"); - return 1; - } - - zenFS.reset(); - - zbd = zbd_open(false, true); - ZonedBlockDevice *zbdRaw = zbd.get(); - zenFS.reset(new ZenFS(zbd.release(), FileSystem::Default(), nullptr)); - - if (FLAGS_aux_path.back() != '/') FLAGS_aux_path.append("/"); - - s = zenFS->MkFS(FLAGS_aux_path, FLAGS_finish_threshold); - if (!s.ok()) { - fprintf(stderr, "Failed to create file system, error: %s\n", - s.ToString().c_str()); - return 1; - } - - fprintf(stdout, "ZenFS file system created. Free space: %lu MB\n", - zbdRaw->GetFreeSpace() / (1024 * 1024)); - - return 0; + return zenfs_mkfs(std::filesystem::path(FLAGS_zbd), + std::filesystem::path(FLAGS_aux_path), + FLAGS_finish_threshold, FLAGS_force); } void list_children(const std::unique_ptr &zenFS, @@ -231,7 +109,7 @@ void list_children(const std::unique_ptr &zenFS, int zenfs_tool_list() { Status s; - std::unique_ptr zbd = zbd_open(true, false); + std::unique_ptr zbd = zbd_open(FLAGS_zbd, true, false); if (!zbd) return 1; std::unique_ptr zenFS; @@ -249,7 +127,7 @@ int zenfs_tool_list() { int zenfs_tool_df() { Status s; - std::unique_ptr zbd = zbd_open(true, false); + std::unique_ptr zbd = zbd_open(FLAGS_zbd, true, false); if (!zbd) return 1; ZonedBlockDevice *zbdRaw = zbd.get(); @@ -469,14 +347,14 @@ int zenfs_tool_backup() { IOStatus io_status; IOOptions opts; IODebugContext dbg; - std::unique_ptr zbd = zbd_open(true, true); + std::unique_ptr zbd = zbd_open(FLAGS_zbd, true, true); if (!zbd) { if (FLAGS_force) { fprintf(stderr, "WARNING: attempting to back up a zoned block device in use! " "Expect data loss and corruption.\n"); - zbd = zbd_open(true, false); + zbd = zbd_open(FLAGS_zbd, true, false); } } @@ -680,7 +558,7 @@ int zenfs_tool_restore() { AddDirSeparatorAtEnd(FLAGS_path); ReadWriteLifeTimeHints(); - std::unique_ptr zbd = zbd_open(false, true); + std::unique_ptr zbd = zbd_open(FLAGS_zbd, false, true); if (!zbd) return 1; std::unique_ptr zenFS; @@ -710,7 +588,7 @@ int zenfs_tool_restore() { int zenfs_tool_dump() { Status s; - std::unique_ptr zbd = zbd_open(true, false); + std::unique_ptr zbd = zbd_open(FLAGS_zbd, true, false); if (!zbd) return 1; ZonedBlockDevice *zbdRaw = zbd.get(); @@ -734,7 +612,7 @@ int zenfs_tool_dump() { int zenfs_tool_fsinfo() { Status s; - std::unique_ptr zbd = zbd_open(true, false); + std::unique_ptr zbd = zbd_open(FLAGS_zbd, true, false); if (!zbd) return 1; std::unique_ptr zenFS; diff --git a/zenfs.mk b/zenfs.mk index 2477f0ba..adff192f 100644 --- a/zenfs.mk +++ b/zenfs.mk @@ -1,5 +1,18 @@ -zenfs_SOURCES = fs/fs_zenfs.cc fs/zbd_zenfs.cc fs/io_zenfs.cc -zenfs_HEADERS = fs/fs_zenfs.h fs/zbd_zenfs.h fs/io_zenfs.h fs/version.h fs/metrics.h fs/snapshot.h +zenfs_SOURCES = \ + fs/fs_zenfs.cc \ + fs/zbd_zenfs.cc \ + fs/io_zenfs.cc \ + fs/util.cc + +zenfs_HEADERS = \ + fs/fs_zenfs.h \ + fs/zbd_zenfs.h \ + fs/io_zenfs.h \ + fs/version.h \ + fs/metrics.h \ + fs/snapshot.h \ + fs/util.h + zenfs_LDFLAGS = -u zenfs_filesystem_reg ZENFS_ROOT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))