]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
libcephfs: fix crash on getpwd
authorJohn Spray <john.spray@redhat.com>
Thu, 3 Mar 2016 11:59:21 +0000 (11:59 +0000)
committerJohn Spray <john.spray@redhat.com>
Mon, 14 Mar 2016 12:32:56 +0000 (12:32 +0000)
...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 <john.spray@redhat.com>
src/client/Client.cc
src/client/Client.h
src/client/SyntheticClient.cc
src/libcephfs.cc
src/test/pybind/test_cephfs.py

index 53984d29059d9f934daaa45684d0bb75dbffb74a..206e1dd1eb36f910ee8505b1d21a38bdad079861 100644 (file)
@@ -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;
index 67b5c5e9c813ba3fd7af073d4ea872536ad3fe41..d53ca1df169a44b1609167991e76d1773f61cd53 100644 (file)
@@ -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
index 78fd7ce51200e6e3c4855280e244a2d2567f69af..b2ef93ae30ba5c151eb12c4cf7d970987d3383fe 100644 (file)
@@ -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);
index 037a018a595686783eb617147a13cabf1a32aa62..b01cf227abb2e4b7f717f647f4ad083352768b76 100644 (file)
@@ -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,
index d2f3eb640596c415ec864ca44fdc2b12f16208c0..77cd31bf994675aa4ed956d57079dd428f631ee6 100644 (file)
@@ -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())