|
1 | 1 |
|
2 | 2 | #include "util.h"
|
3 | 3 |
|
4 |
| -#include <dirent.h> |
5 | 4 | #include <libzbd/zbd.h>
|
6 |
| -#include <sys/stat.h> |
7 |
| -#include <sys/types.h> |
8 | 5 | #include <unistd.h>
|
9 | 6 |
|
10 | 7 | #include <cstdint>
|
|
16 | 13 |
|
17 | 14 | namespace ROCKSDB_NAMESPACE {
|
18 | 15 |
|
19 |
| -std::unique_ptr<ZonedBlockDevice> zbd_open(std::string const &zbd_path, |
20 |
| - bool readonly, bool exclusive) { |
21 |
| - std::unique_ptr<ZonedBlockDevice> zbd{ |
22 |
| - new ZonedBlockDevice(zbd_path, nullptr)}; |
23 |
| - IOStatus open_status = zbd->Open(readonly, exclusive); |
| 16 | +IOStatus zenfs_zbd_open(std::filesystem::path const &path, bool readonly, |
| 17 | + bool exclusive, |
| 18 | + std::unique_ptr<ZonedBlockDevice> &out_zbd) { |
| 19 | + out_zbd = |
| 20 | + std::unique_ptr<ZonedBlockDevice>{new ZonedBlockDevice(path, nullptr)}; |
| 21 | + IOStatus status = out_zbd->Open(readonly, exclusive); |
24 | 22 |
|
25 |
| - if (!open_status.ok()) { |
| 23 | + if (!status.ok()) { |
26 | 24 | fprintf(stderr, "Failed to open zoned block device: %s, error: %s\n",
|
27 |
| - zbd_path.c_str(), open_status.ToString().c_str()); |
28 |
| - zbd.reset(); |
| 25 | + path.c_str(), status.ToString().c_str()); |
| 26 | + out_zbd.reset(); |
29 | 27 | }
|
30 | 28 |
|
31 |
| - return zbd; |
| 29 | + return status; |
32 | 30 | }
|
33 | 31 |
|
34 |
| -// Here we pass 'zbd' by non-const reference to be able to pass its ownership |
35 |
| -// to 'zenFS' |
36 |
| -Status zenfs_mount(std::unique_ptr<ZonedBlockDevice> &zbd, |
37 |
| - std::unique_ptr<ZenFS> *zenFS, bool readonly) { |
38 |
| - Status s; |
39 |
| - |
40 |
| - std::unique_ptr<ZenFS> localZenFS{ |
41 |
| - new ZenFS(zbd.release(), FileSystem::Default(), nullptr)}; |
42 |
| - s = localZenFS->Mount(readonly); |
43 |
| - if (!s.ok()) { |
44 |
| - localZenFS.reset(); |
| 32 | +Status zenfs_mount(std::unique_ptr<ZonedBlockDevice> &zbd, bool readonly, |
| 33 | + std::unique_ptr<ZenFS> &out_zen_fs) { |
| 34 | + Status status; |
| 35 | + |
| 36 | + out_zen_fs = std::unique_ptr<ZenFS>{ |
| 37 | + new ZenFS(std::move(zbd), FileSystem::Default(), nullptr)}; |
| 38 | + status = out_zen_fs->Mount(readonly); |
| 39 | + if (!status.ok()) { |
| 40 | + out_zen_fs.reset(); |
45 | 41 | }
|
46 |
| - *zenFS = std::move(localZenFS); |
47 | 42 |
|
48 |
| - return s; |
| 43 | + return status; |
49 | 44 | }
|
50 | 45 |
|
51 |
| -static int is_dir(const char *path) { |
52 |
| - struct stat st; |
53 |
| - if (stat(path, &st) != 0) { |
54 |
| - fprintf(stderr, "Failed to stat %s\n", path); |
55 |
| - return 1; |
56 |
| - } |
57 |
| - return S_ISDIR(st.st_mode); |
| 46 | +static Status zenfs_exists(std::filesystem::path const &zbd_path, |
| 47 | + bool &out_exists) { |
| 48 | + Status status; |
| 49 | + std::unique_ptr<ZonedBlockDevice> zbd; |
| 50 | + std::unique_ptr<ZenFS> zen_fs; |
| 51 | + |
| 52 | + status = zenfs_zbd_open(zbd_path, false, true, zbd); |
| 53 | + if (!status.ok()) return Status::IOError("Failed to open ZBD"); |
| 54 | + |
| 55 | + status = zenfs_mount(zbd, false, zen_fs); |
| 56 | + out_exists = status.ok() || !status.IsNotFound(); |
| 57 | + |
| 58 | + return Status::OK(); |
58 | 59 | }
|
59 | 60 |
|
60 | 61 | // Create or check pre-existing aux directory and fail if it is
|
61 | 62 | // inaccessible by current user and if it has previous data
|
62 |
| -static int create_aux_dir(const char *path) { |
63 |
| - struct dirent *dent; |
64 |
| - size_t nfiles = 0; |
65 |
| - int ret = 0; |
66 |
| - |
67 |
| - errno = 0; |
68 |
| - ret = mkdir(path, 0750); |
69 |
| - if (ret < 0 && EEXIST != errno) { |
70 |
| - fprintf(stderr, "Failed to create aux directory %s: %s\n", path, |
71 |
| - strerror(errno)); |
72 |
| - return 1; |
| 63 | +static Status create_aux_dir(std::filesystem::path const &path) { |
| 64 | + namespace fs = std::filesystem; |
| 65 | + std::error_code ec; |
| 66 | + |
| 67 | + bool aux_exists = fs::exists(path, ec); |
| 68 | + if (ec) { |
| 69 | + return Status::Aborted("Failed to check if aux directory exists: " + |
| 70 | + ec.message()); |
| 71 | + } |
| 72 | + |
| 73 | + bool aux_is_dir = false; |
| 74 | + if (aux_exists) { |
| 75 | + aux_is_dir = fs::is_directory(path, ec); |
| 76 | + if (ec) { |
| 77 | + return Status::Aborted("Failed to check if aux_dir is directory" + |
| 78 | + ec.message()); |
| 79 | + } |
73 | 80 | }
|
74 |
| - // The aux_path is now available, check if it is a directory infact |
75 |
| - // and is empty and the user has access permission |
76 | 81 |
|
77 |
| - if (!is_dir(path)) { |
78 |
| - fprintf(stderr, "Aux path %s is not a directory\n", path); |
79 |
| - return 1; |
| 82 | + if (aux_exists && !aux_is_dir) { |
| 83 | + return Status::Aborted("Aux path exists but is not a directory"); |
80 | 84 | }
|
81 | 85 |
|
82 |
| - errno = 0; |
83 |
| - |
84 |
| - auto closedirDeleter = [](DIR *d) { |
85 |
| - if (d != nullptr) closedir(d); |
86 |
| - }; |
87 |
| - std::unique_ptr<DIR, decltype(closedirDeleter)> aux_dir{ |
88 |
| - opendir(path), std::move(closedirDeleter)}; |
89 |
| - if (errno) { |
90 |
| - fprintf(stderr, "Failed to open aux directory %s: %s\n", path, |
91 |
| - strerror(errno)); |
92 |
| - return 1; |
| 86 | + if (!aux_exists) { |
| 87 | + if (!fs::create_directory(path, ec) || ec) { |
| 88 | + return Status::IOError("Failed to create aux path:" + ec.message()); |
| 89 | + } |
| 90 | + |
| 91 | + fs::permissions( |
| 92 | + path, |
| 93 | + fs::perms::owner_all | fs::perms::group_read | fs::perms::group_exec, |
| 94 | + ec); |
| 95 | + if (ec) { |
| 96 | + return Status::IOError("Failed to set permissions on aux path:" + |
| 97 | + ec.message()); |
| 98 | + } |
93 | 99 | }
|
94 | 100 |
|
95 |
| - // Consider the directory as non-empty if any files/dir other |
96 |
| - // than . and .. are found. |
97 |
| - while ((dent = readdir(aux_dir.get())) != NULL && nfiles <= 2) ++nfiles; |
98 |
| - if (nfiles > 2) { |
99 |
| - fprintf(stderr, "Aux directory %s is not empty.\n", path); |
100 |
| - return 1; |
| 101 | + if (access(path.c_str(), R_OK | W_OK | X_OK) < 0) { |
| 102 | + return Status::Aborted( |
| 103 | + "User does not have access permissions on aux directory " + |
| 104 | + path.string()); |
101 | 105 | }
|
102 | 106 |
|
103 |
| - if (access(path, R_OK | W_OK | X_OK) < 0) { |
104 |
| - fprintf(stderr, |
105 |
| - "User does not have access permissions on " |
106 |
| - "aux directory %s\n", |
107 |
| - path); |
108 |
| - return 1; |
| 107 | + if (std::distance(fs::directory_iterator{path}, {}) > 2) { |
| 108 | + return Status::Aborted("Aux directory " + path.string() + " is not empty"); |
109 | 109 | }
|
110 | 110 |
|
111 |
| - return 0; |
| 111 | + return Status::OK(); |
112 | 112 | }
|
113 | 113 |
|
114 |
| -int zenfs_mkfs(std::string const &zbd_path, std::string const &aux_path, |
115 |
| - int finish_threshold, bool force) { |
116 |
| - Status s; |
| 114 | +static Status zenfs_create(std::filesystem::path const &zbd_path, |
| 115 | + std::filesystem::path const &aux_path, |
| 116 | + uint32_t finish_threshold |
117 | 117 |
|
118 |
| - if (create_aux_dir(aux_path.c_str())) return 1; |
| 118 | +) { |
| 119 | + Status status; |
| 120 | + std::unique_ptr<ZonedBlockDevice> zbd; |
| 121 | + std::unique_ptr<ZenFS> zen_fs; |
119 | 122 |
|
120 |
| - std::unique_ptr<ZonedBlockDevice> zbd = zbd_open(zbd_path, false, true); |
121 |
| - if (!zbd) return 1; |
| 123 | + status = create_aux_dir(aux_path); |
| 124 | + if (!status.ok()) return status; |
122 | 125 |
|
123 |
| - std::unique_ptr<ZenFS> zenFS; |
124 |
| - s = zenfs_mount(zbd, &zenFS, false); |
125 |
| - if ((s.ok() || !s.IsNotFound()) && !force) { |
126 |
| - fprintf( |
127 |
| - stderr, |
128 |
| - "Existing filesystem found, use --force if you want to replace it.\n"); |
129 |
| - return 1; |
| 126 | + status = zenfs_zbd_open(zbd_path, false, true, zbd); |
| 127 | + if (!status.ok()) { |
| 128 | + return status; |
130 | 129 | }
|
131 | 130 |
|
132 |
| - zenFS.reset(); |
133 |
| - |
134 |
| - zbd = zbd_open(zbd_path, false, true); |
135 |
| - ZonedBlockDevice *zbdRaw = zbd.get(); |
136 |
| - zenFS.reset(new ZenFS(zbd.release(), FileSystem::Default(), nullptr)); |
| 131 | + zen_fs.reset(new ZenFS(std::move(zbd), FileSystem::Default(), nullptr)); |
137 | 132 |
|
138 | 133 | std::string aux_path_patched = aux_path;
|
139 | 134 | if (aux_path_patched.back() != '/') aux_path_patched.append("/");
|
140 | 135 |
|
141 |
| - s = zenFS->MkFS(aux_path_patched, finish_threshold); |
142 |
| - if (!s.ok()) { |
143 |
| - fprintf(stderr, "Failed to create file system, error: %s\n", |
144 |
| - s.ToString().c_str()); |
145 |
| - return 1; |
| 136 | + status = zen_fs->MkFS(aux_path_patched, finish_threshold); |
| 137 | + if (!status.ok()) { |
| 138 | + return status; |
146 | 139 | }
|
147 | 140 |
|
148 |
| - fprintf(stdout, "ZenFS file system created. Free space: %lu MB\n", |
149 |
| - zbdRaw->GetFreeSpace() / (1024 * 1024)); |
| 141 | + return status; |
| 142 | +} |
| 143 | + |
| 144 | +Status zenfs_mkfs(std::filesystem::path const &zbd_path, |
| 145 | + std::filesystem::path const &aux_path, |
| 146 | + uint32_t finish_threshold, bool force) { |
| 147 | + Status status; |
| 148 | + bool exists = false; |
| 149 | + |
| 150 | + status = zenfs_exists(zbd_path, exists); |
| 151 | + if (!status.ok()) { |
| 152 | + return status; |
| 153 | + } |
150 | 154 |
|
151 |
| - return 0; |
| 155 | + if (exists && !force) { |
| 156 | + return Status::Aborted( |
| 157 | + "Existing filesystem found, use --force if you want to replace " |
| 158 | + "it."); |
| 159 | + } |
| 160 | + |
| 161 | + return zenfs_create(zbd_path, aux_path, finish_threshold); |
152 | 162 | }
|
| 163 | + |
153 | 164 | } // namespace ROCKSDB_NAMESPACE
|
0 commit comments