Skip to content

Commit 4cbf549

Browse files
committed
Merge PR ceph#62228 into main
* refs/pull/62228/head: libcephfs: getcwd after chdir for API constraint client: unwrap dentries for getcwd client: refactor / optimize chdir test/libcephfs: test getcwd with case insensitive dir test/libcephfs: refactor ManyNestedDirs include/filepath: add iterators for components Reviewed-by: Venky Shankar <[email protected]>
2 parents 5944da8 + c7c5089 commit 4cbf549

File tree

6 files changed

+115
-40
lines changed

6 files changed

+115
-40
lines changed

src/client/Client.cc

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12298,10 +12298,7 @@ int Client::statxat(int dirfd, const char *relpath,
1229812298
return r;
1229912299
}
1230012300

12301-
// not written yet, but i want to link!
12302-
12303-
int Client::chdir(const char *relpath, std::string &new_cwd,
12304-
const UserPerm& perms)
12301+
int Client::chdir(const char *relpath, const UserPerm& perms)
1230512302
{
1230612303
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
1230712304
if (!mref_reader.is_state_satisfied())
@@ -12317,29 +12314,28 @@ int Client::chdir(const char *relpath, std::string &new_cwd,
1231712314
return rc;
1231812315
}
1231912316

12320-
if (!(in.get()->is_dir()))
12317+
if (!in->is_dir())
1232112318
return -ENOTDIR;
1232212319

12323-
if (cwd != in)
12324-
cwd.swap(in);
12320+
cwd = std::move(in);
12321+
1232512322
ldout(cct, 3) << "chdir(" << relpath << ") cwd now " << cwd->ino << dendl;
1232612323

12327-
_getcwd(new_cwd, perms);
1232812324
return 0;
1232912325
}
1233012326

12331-
void Client::_getcwd(string& dir, const UserPerm& perms)
12327+
int Client::_getcwd(string& dir, const UserPerm& perms)
1233212328
{
1233312329
filepath path;
1233412330
ldout(cct, 10) << __func__ << " " << *cwd << dendl;
1233512331

12336-
Inode *in = cwd.get();
12337-
while (in != root.get()) {
12332+
auto in = cwd;
12333+
while (in != root) {
1233812334
ceph_assert(in->dentries.size() < 2); // dirs can't be hard-linked
1233912335

1234012336
// A cwd or ancester is unlinked
1234112337
if (in->dentries.empty()) {
12342-
return;
12338+
return -ENOENT;
1234312339
}
1234412340

1234512341
Dentry *dn = in->get_first_parent();
@@ -12358,25 +12354,28 @@ void Client::_getcwd(string& dir, const UserPerm& perms)
1235812354

1235912355
// start over
1236012356
path = filepath();
12361-
in = cwd.get();
12357+
in = cwd;
1236212358
continue;
1236312359
}
12364-
path.push_front_dentry(dn->name);
12365-
in = dn->dir->parent_inode;
12360+
auto* diri = dn->dir->parent_inode;
12361+
ceph_assert(diri);
12362+
auto dname = _unwrap_name(*diri, dn->name, dn->alternate_name);
12363+
path.push_front_dentry(dname);
12364+
in = InodeRef(diri);
1236612365
}
1236712366
dir = "/";
1236812367
dir += path.get_path();
12368+
return 0;
1236912369
}
1237012370

12371-
void Client::getcwd(string& dir, const UserPerm& perms)
12371+
int Client::getcwd(string& dir, const UserPerm& perms)
1237212372
{
1237312373
RWRef_t mref_reader(mount_state, CLIENT_MOUNTING);
1237412374
if (!mref_reader.is_state_satisfied())
12375-
return;
12375+
return -ENOTCONN;
1237612376

1237712377
std::scoped_lock l(client_lock);
12378-
12379-
_getcwd(dir, perms);
12378+
return _getcwd(dir, perms);
1238012379
}
1238112380

1238212381
int Client::statfs(const char *path, struct statvfs *stbuf,

src/client/Client.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,9 @@ class Client : public Dispatcher, public md_config_obs_t {
343343
// these should (more or less) mirror the actual system calls.
344344
int statfs(const char *path, struct statvfs *stbuf, const UserPerm& perms);
345345

346-
// crap
347-
int chdir(const char *s, std::string &new_cwd, const UserPerm& perms);
348-
void _getcwd(std::string& cwd, const UserPerm& perms);
349-
void getcwd(std::string& cwd, const UserPerm& perms);
346+
int chdir(const char *path, const UserPerm& perms);
347+
int _getcwd(std::string& cwd, const UserPerm& perms);
348+
int getcwd(std::string& cwd, const UserPerm& perms);
350349

351350
// namespace ops
352351
int opendir(const char *name, dir_result_t **dirpp, const UserPerm& perms);

src/client/SyntheticClient.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,8 +1219,7 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only)
12191219
const char *a = t.get_string(buf, p);
12201220
// Client users should remember their path, but since this
12211221
// is just a synthetic client we ignore it.
1222-
std::string ignore;
1223-
client->chdir(a, ignore, perms);
1222+
client->chdir(a, perms);
12241223
} else if (strcmp(op, "statfs") == 0) {
12251224
struct statvfs stbuf;
12261225
client->statfs("/", &stbuf, perms);

src/include/filepath.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,24 @@ class filepath {
130130
return bits[i];
131131
}
132132

133+
auto begin() const {
134+
if (bits.empty() && path.length() > 0) parse_bits();
135+
return std::as_const(bits).begin();
136+
}
137+
auto rbegin() const {
138+
if (bits.empty() && path.length() > 0) parse_bits();
139+
return std::as_const(bits).rbegin();
140+
}
141+
142+
auto end() const {
143+
if (bits.empty() && path.length() > 0) parse_bits();
144+
return std::as_const(bits).end();
145+
}
146+
auto rend() const {
147+
if (bits.empty() && path.length() > 0) parse_bits();
148+
return std::as_const(bits).rend();
149+
}
150+
133151
const std::string& last_dentry() const {
134152
if (bits.empty() && path.length() > 0) parse_bits();
135153
ceph_assert(!bits.empty());

src/libcephfs.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,15 @@ struct ceph_mount_info
322322

323323
int chdir(const char *to, const UserPerm& perms)
324324
{
325-
return client->chdir(to, cwd, perms);
325+
int rc = client->chdir(to, perms);
326+
if (rc == 0) {
327+
/* Current API requires "cwd" to be refreshed after every chdir so that
328+
* getcwd on an unlinked cwd will still return the old path. Note:
329+
* Client::getcwd now returns an error but leaves the "cwd" string
330+
* unmodified for this purpose. */
331+
client->getcwd(cwd, perms);
332+
}
333+
return rc;
326334
}
327335

328336
CephContext *get_ceph_context() const {

src/test/libcephfs/test.cc

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*/
1414

1515
#include "include/compat.h"
16+
#include "include/filepath.h"
1617
#include "gtest/gtest.h"
1718
#include "include/cephfs/libcephfs.h"
1819
#include "mds/mdstypes.h"
@@ -521,40 +522,91 @@ TEST(LibCephFS, ManyNestedDirs) {
521522
ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
522523
ASSERT_EQ(ceph_mount(cmount, NULL), 0);
523524

524-
const char *many_path = "a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a";
525+
static const char many_path[] = "/ManyNestedDirs/A/a/a/a/a/b/B/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/Aa";
526+
const filepath mfp = filepath(many_path);
525527
ASSERT_EQ(ceph_mkdirs(cmount, many_path, 0755), 0);
526528

527-
int i = 0;
529+
for (auto& component : mfp) {
530+
struct ceph_dir_result *dirp;
531+
ASSERT_EQ(ceph_opendir(cmount, ".", &dirp), 0);
532+
struct dirent *dent = ceph_readdir(cmount, dirp);
533+
ASSERT_TRUE(dent != NULL);
534+
ASSERT_STREQ(dent->d_name, ".");
535+
dent = ceph_readdir(cmount, dirp);
536+
ASSERT_TRUE(dent != NULL);
537+
ASSERT_STREQ(dent->d_name, "..");
538+
if (component == "ManyNestedDirs"sv) {
539+
ASSERT_EQ(0, ceph_chdir(cmount, component.c_str()));
540+
continue;
541+
}
542+
dent = ceph_readdir(cmount, dirp);
543+
ASSERT_TRUE(dent != NULL);
544+
ASSERT_STREQ(component.c_str(), dent->d_name);
545+
ASSERT_EQ(ceph_chdir(cmount, dent->d_name), 0);
546+
ASSERT_EQ(ceph_closedir(cmount, dirp), 0);
547+
}
548+
549+
{
550+
auto* cwd = ceph_getcwd(cmount);
551+
ASSERT_STREQ(cwd, many_path);
552+
}
553+
554+
for (auto it = mfp.rbegin(); it != mfp.rend(); ++it) {
555+
auto& component = *it;
556+
ASSERT_EQ(ceph_chdir(cmount, ".."), 0);
557+
ASSERT_EQ(ceph_rmdir(cmount, component.c_str()), 0);
558+
}
559+
560+
ASSERT_STREQ(ceph_getcwd(cmount), "/");
561+
562+
ceph_shutdown(cmount);
563+
}
564+
565+
TEST(LibCephFS, ManyNestedDirsCaseInsensitive) {
566+
struct ceph_mount_info *cmount;
567+
ASSERT_EQ(ceph_create(&cmount, NULL), 0);
568+
ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0);
569+
ASSERT_EQ(0, ceph_conf_parse_env(cmount, NULL));
570+
ASSERT_EQ(ceph_mount(cmount, NULL), 0);
528571

529-
for(; i < 39; ++i) {
530-
ASSERT_EQ(ceph_chdir(cmount, "a"), 0);
572+
static const char many_path[] = "/ManyNestedDirsCaseInsensitive/A/a/a/a/a/b/B/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/Aa";
573+
const filepath mfp = filepath(many_path);
574+
ASSERT_EQ(0, ceph_mkdir(cmount, mfp[0].c_str(), 0755));
575+
ASSERT_EQ(0, ceph_setxattr(cmount, mfp[0].c_str(), "ceph.dir.casesensitive", (void *) "0", 1, XATTR_CREATE));
576+
ASSERT_EQ(ceph_mkdirs(cmount, many_path, 0755), 0);
531577

578+
for (auto& component : mfp) {
532579
struct ceph_dir_result *dirp;
533-
ASSERT_EQ(ceph_opendir(cmount, "a", &dirp), 0);
580+
ASSERT_EQ(ceph_opendir(cmount, ".", &dirp), 0);
534581
struct dirent *dent = ceph_readdir(cmount, dirp);
535582
ASSERT_TRUE(dent != NULL);
536583
ASSERT_STREQ(dent->d_name, ".");
537584
dent = ceph_readdir(cmount, dirp);
538585
ASSERT_TRUE(dent != NULL);
539586
ASSERT_STREQ(dent->d_name, "..");
587+
if (component == "ManyNestedDirsCaseInsensitive"sv) {
588+
ASSERT_EQ(0, ceph_chdir(cmount, component.c_str()));
589+
continue;
590+
}
540591
dent = ceph_readdir(cmount, dirp);
541592
ASSERT_TRUE(dent != NULL);
542-
ASSERT_STREQ(dent->d_name, "a");
593+
ASSERT_STREQ(component.c_str(), dent->d_name);
594+
ASSERT_EQ(ceph_chdir(cmount, dent->d_name), 0);
543595
ASSERT_EQ(ceph_closedir(cmount, dirp), 0);
544596
}
545597

546-
ASSERT_STREQ(ceph_getcwd(cmount), "/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a");
547-
548-
ASSERT_EQ(ceph_chdir(cmount, "a/a/a"), 0);
598+
{
599+
auto* cwd = ceph_getcwd(cmount);
600+
ASSERT_STREQ(cwd, many_path);
601+
}
549602

550-
for(i = 0; i < 39; ++i) {
603+
for (auto it = mfp.rbegin(); it != mfp.rend(); ++it) {
604+
auto& component = *it;
551605
ASSERT_EQ(ceph_chdir(cmount, ".."), 0);
552-
ASSERT_EQ(ceph_rmdir(cmount, "a"), 0);
606+
ASSERT_EQ(ceph_rmdir(cmount, component.c_str()), 0);
553607
}
554608

555-
ASSERT_EQ(ceph_chdir(cmount, "/"), 0);
556-
557-
ASSERT_EQ(ceph_rmdir(cmount, "a/a/a"), 0);
609+
ASSERT_STREQ(ceph_getcwd(cmount), "/");
558610

559611
ceph_shutdown(cmount);
560612
}

0 commit comments

Comments
 (0)