Skip to content

Commit 6d57640

Browse files
committed
util,fs: Fix parameter handling in utility functions
Closes westerndigitalcorporation#97. Signed-off-by: Andreas Hindborg <[email protected]>
1 parent 4633176 commit 6d57640

File tree

5 files changed

+209
-166
lines changed

5 files changed

+209
-166
lines changed

fs/fs_zenfs.cc

+13-12
Original file line numberDiff line numberDiff line change
@@ -235,9 +235,9 @@ IOStatus ZenMetaLog::ReadRecord(Slice* record, std::string* scratch) {
235235
return IOStatus::OK();
236236
}
237237

238-
ZenFS::ZenFS(ZonedBlockDevice* zbd, std::shared_ptr<FileSystem> aux_fs,
239-
std::shared_ptr<Logger> logger)
240-
: FileSystemWrapper(aux_fs), zbd_(zbd), logger_(logger) {
238+
ZenFS::ZenFS(std::unique_ptr<ZonedBlockDevice> zbd,
239+
std::shared_ptr<FileSystem> aux_fs, std::shared_ptr<Logger> logger)
240+
: FileSystemWrapper(aux_fs), zbd_(zbd.release()), logger_(logger) {
241241
Info(logger_, "ZenFS initializing");
242242
Info(logger_, "ZenFS parameters: block device: %s, aux filesystem: %s",
243243
zbd_->GetFilename().c_str(), target()->Name());
@@ -271,9 +271,8 @@ IOStatus ZenFS::Repair() {
271271
return IOStatus::OK();
272272
}
273273

274-
std::string ZenFS::FormatPathLexically(std::filesystem::path filepath) {
275-
std::filesystem::path ret = "/" / filepath.lexically_normal();
276-
return ret.string();
274+
std::filesystem::path FormatPathLexically(std::filesystem::path filepath) {
275+
return "/" / filepath.lexically_normal();
277276
}
278277

279278
void ZenFS::LogFiles() {
@@ -1422,14 +1421,15 @@ Status ZenFS::Mount(bool readonly) {
14221421
return Status::OK();
14231422
}
14241423

1425-
Status ZenFS::MkFS(std::string aux_fs_p, uint32_t finish_threshold) {
1424+
Status ZenFS::MkFS(std::filesystem::path const& aux_fs_path,
1425+
uint32_t finish_threshold) {
14261426
std::vector<Zone*> metazones = zbd_->GetMetaZones();
14271427
std::unique_ptr<ZenMetaLog> log;
14281428
Zone* meta_zone = nullptr;
1429-
std::string aux_fs_path = FormatPathLexically(aux_fs_p);
1429+
std::filesystem::path aux_fs_path_normal = FormatPathLexically(aux_fs_path);
14301430
IOStatus s;
14311431

1432-
if (aux_fs_path.length() > 255) {
1432+
if (aux_fs_path_normal.string().length() > 255) {
14331433
return Status::InvalidArgument(
14341434
"Aux filesystem path must be less than 256 bytes\n");
14351435
}
@@ -1467,7 +1467,7 @@ Status ZenFS::MkFS(std::string aux_fs_p, uint32_t finish_threshold) {
14671467

14681468
log.reset(new ZenMetaLog(zbd_, meta_zone));
14691469

1470-
Superblock super(zbd_, aux_fs_path, finish_threshold);
1470+
Superblock super(zbd_, aux_fs_path_normal, finish_threshold);
14711471
std::string super_string;
14721472
super.EncodeTo(&super_string);
14731473

@@ -1533,15 +1533,16 @@ Status NewZenFS(FileSystem** fs, const std::string& bdevname,
15331533
}
15341534
#endif
15351535

1536-
ZonedBlockDevice* zbd = new ZonedBlockDevice(bdevname, logger, metrics);
1536+
std::unique_ptr<ZonedBlockDevice> zbd{
1537+
new ZonedBlockDevice(bdevname, logger, metrics)};
15371538
IOStatus zbd_status = zbd->Open(false, true);
15381539
if (!zbd_status.ok()) {
15391540
Error(logger, "mkfs: Failed to open zoned block device: %s",
15401541
zbd_status.ToString().c_str());
15411542
return Status::IOError(zbd_status.ToString());
15421543
}
15431544

1544-
ZenFS* zenFS = new ZenFS(zbd, FileSystem::Default(), logger);
1545+
ZenFS* zenFS = new ZenFS(std::move(zbd), FileSystem::Default(), logger);
15451546
s = zenFS->Mount(false);
15461547
if (!s.ok()) {
15471548
delete zenFS;

fs/fs_zenfs.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "metrics.h"
1414
#include "rocksdb/env.h"
1515
#include "rocksdb/file_system.h"
16-
#include "rocksdb/status.h"
1716
#include "snapshot.h"
1817
#include "version.h"
1918
#include "zbd_zenfs.h"
@@ -155,7 +154,6 @@ class ZenFS : public FileSystemWrapper {
155154

156155
void LogFiles();
157156
void ClearFiles();
158-
std::string FormatPathLexically(std::filesystem::path filepath);
159157
IOStatus WriteSnapshotLocked(ZenMetaLog* meta_log);
160158
IOStatus WriteEndRecord(ZenMetaLog* meta_log);
161159
IOStatus RollMetaZoneLocked();
@@ -259,12 +257,14 @@ class ZenFS : public FileSystemWrapper {
259257
IODebugContext* dbg, bool reopen);
260258

261259
public:
262-
explicit ZenFS(ZonedBlockDevice* zbd, std::shared_ptr<FileSystem> aux_fs,
260+
explicit ZenFS(std::unique_ptr<ZonedBlockDevice> zbd,
261+
std::shared_ptr<FileSystem> aux_fs,
263262
std::shared_ptr<Logger> logger);
264263
virtual ~ZenFS();
265264

266265
Status Mount(bool readonly);
267-
Status MkFS(std::string aux_fs_path, uint32_t finish_threshold);
266+
Status MkFS(std::filesystem::path const& aux_fs_path,
267+
uint32_t finish_threshold);
268268
std::map<std::string, Env::WriteLifeTimeHint> GetWriteLifeTimeHints();
269269

270270
const char* Name() const override {
@@ -441,6 +441,9 @@ class ZenFS : public FileSystemWrapper {
441441
const std::string& fname,
442442
const std::vector<ZoneExtentSnapshot*>& migrate_exts);
443443
};
444+
445+
std::filesystem::path FormatPathLexically(std::filesystem::path filepath);
446+
444447
#endif // !defined(ROCKSDB_LITE) && defined(OS_LINUX)
445448

446449
Status NewZenFS(

fs/util.cc

+109-98
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11

22
#include "util.h"
33

4-
#include <dirent.h>
54
#include <libzbd/zbd.h>
6-
#include <sys/stat.h>
7-
#include <sys/types.h>
85
#include <unistd.h>
96

107
#include <cstdint>
@@ -16,138 +13,152 @@
1613

1714
namespace ROCKSDB_NAMESPACE {
1815

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);
2422

25-
if (!open_status.ok()) {
23+
if (!status.ok()) {
2624
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();
2927
}
3028

31-
return zbd;
29+
return status;
3230
}
3331

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();
4541
}
46-
*zenFS = std::move(localZenFS);
4742

48-
return s;
43+
return status;
4944
}
5045

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();
5859
}
5960

6061
// Create or check pre-existing aux directory and fail if it is
6162
// 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+
}
7380
}
74-
// The aux_path is now available, check if it is a directory infact
75-
// and is empty and the user has access permission
7681

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");
8084
}
8185

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+
}
9399
}
94100

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());
101105
}
102106

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");
109109
}
110110

111-
return 0;
111+
return Status::OK();
112112
}
113113

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
117117

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;
119122

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;
122125

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;
130129
}
131130

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));
137132

138133
std::string aux_path_patched = aux_path;
139134
if (aux_path_patched.back() != '/') aux_path_patched.append("/");
140135

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;
146139
}
147140

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+
}
150154

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);
152162
}
163+
153164
} // namespace ROCKSDB_NAMESPACE

fs/util.h

+8-6
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@
88

99
namespace ROCKSDB_NAMESPACE {
1010

11-
std::unique_ptr<ZonedBlockDevice> zbd_open(std::string const& zbd_path,
12-
bool readonly, bool exclusive);
11+
IOStatus zenfs_zbd_open(std::filesystem::path const &path, bool readonly,
12+
bool exclusive,
13+
std::unique_ptr<ZonedBlockDevice> &out_zbd);
1314

14-
Status zenfs_mount(std::unique_ptr<ZonedBlockDevice>& zbd,
15-
std::unique_ptr<ZenFS>* zenFS, bool readonly);
15+
Status zenfs_mount(std::unique_ptr<ZonedBlockDevice> &zbd, bool readonly,
16+
std::unique_ptr<ZenFS> &out_zen_fs);
1617

17-
int zenfs_mkfs(std::string const& zbd_path, std::string const& aux_path,
18-
int finish_threshold, bool force);
18+
Status zenfs_mkfs(std::filesystem::path const &zbd_path,
19+
std::filesystem::path const &aux_path,
20+
uint32_t finish_threshold, bool force);
1921
} // namespace ROCKSDB_NAMESPACE

0 commit comments

Comments
 (0)