From: John Spray Date: Thu, 3 Mar 2016 11:59:21 +0000 (+0000) Subject: libcephfs: fix crash on getpwd X-Git-Tag: v10.1.1~124^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=85cfa4f1d384b7bbbd811031b7013099aaafe706;p=ceph.git libcephfs: fix crash on getpwd ...if the directory has been unlinked in the background. Previously this would assert out, now it will just give you the last string that you passed into chdir. Signed-off-by: John Spray --- diff --git a/src/client/Client.cc b/src/client/Client.cc index 53984d29059d..206e1dd1eb36 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -8663,7 +8663,7 @@ int Client::fstat(int fd, struct stat *stbuf) // not written yet, but i want to link! -int Client::chdir(const char *relpath) +int Client::chdir(const char *relpath, std::string &new_cwd) { Mutex::Locker lock(client_lock); tout(cct) << "chdir" << std::endl; @@ -8676,6 +8676,8 @@ int Client::chdir(const char *relpath) if (cwd != in) cwd.swap(in); ldout(cct, 3) << "chdir(" << relpath << ") cwd now " << cwd->ino << dendl; + + getcwd(new_cwd); return 0; } @@ -8687,7 +8689,15 @@ void Client::getcwd(string& dir) Inode *in = cwd.get(); while (in != root) { assert(in->dn_set.size() < 2); // dirs can't be hard-linked + + // A cwd or ancester is unlinked + if (in->dn_set.empty()) { + return; + } + Dentry *dn = in->get_first_parent(); + + if (!dn) { // look it up ldout(cct, 10) << "getcwd looking up parent for " << *in << dendl; diff --git a/src/client/Client.h b/src/client/Client.h index 67b5c5e9c813..d53ca1df169a 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -892,7 +892,7 @@ public: int statfs(const char *path, struct statvfs *stbuf); // crap - int chdir(const char *s); + int chdir(const char *s, std::string &new_cwd); void getcwd(std::string& cwd); // namespace ops diff --git a/src/client/SyntheticClient.cc b/src/client/SyntheticClient.cc index 78fd7ce51200..b2ef93ae30ba 100644 --- a/src/client/SyntheticClient.cc +++ b/src/client/SyntheticClient.cc @@ -1206,7 +1206,10 @@ int SyntheticClient::play_trace(Trace& t, string& prefix, bool metadata_only) client->fsync(fd, b); } else if (strcmp(op, "chdir") == 0) { const char *a = t.get_string(buf, p); - client->chdir(a); + // Client users should remember their path, but since this + // is just a synthetic client we ignore it. + std::string ignore; + client->chdir(a, ignore); } else if (strcmp(op, "statfs") == 0) { struct statvfs stbuf; client->statfs("/", &stbuf); diff --git a/src/libcephfs.cc b/src/libcephfs.cc index 037a018a5956..b01cf227abb2 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -231,6 +231,11 @@ public: return cwd.c_str(); } + int chdir(const char *to) + { + return client->chdir(to, cwd); + } + CephContext *get_ceph_context() const { return cct; } @@ -454,7 +459,7 @@ extern "C" int ceph_chdir (struct ceph_mount_info *cmount, const char *s) { if (!cmount->is_mounted()) return -ENOTCONN; - return cmount->get_client()->chdir(s); + return cmount->chdir(s); } extern "C" int ceph_opendir(struct ceph_mount_info *cmount, diff --git a/src/test/pybind/test_cephfs.py b/src/test/pybind/test_cephfs.py index d2f3eb640596..77cd31bf9946 100644 --- a/src/test/pybind/test_cephfs.py +++ b/src/test/pybind/test_cephfs.py @@ -143,3 +143,15 @@ def test_symlink(): cephfs.close(fd) cephfs.unlink('file-2') +@with_setup(setup_test) +def test_delete_cwd(): + assert_equal("/", cephfs.getcwd()) + + cephfs.mkdir("/temp-directory", 0755) + cephfs.chdir("/temp-directory") + cephfs.rmdir("/temp-directory") + + # getcwd gives you something stale here: it remembers the path string + # even when things are unlinked. It's up to the caller to find out + # whether it really still exists + assert_equal("/temp-directory", cephfs.getcwd())