]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
cfuse: Add the parent entry (..) for a top-level readdir
authorSam Lang <sam.lang@inktank.com>
Thu, 20 Sep 2012 00:47:21 +0000 (17:47 -0700)
committerSam Lang <sam.lang@inktank.com>
Thu, 20 Sep 2012 00:47:21 +0000 (17:47 -0700)
In the lowlevel fuse api, the current (.) and parent (..) entries
must be added manually in a readdir call.  For the root directory
the parent is not a ceph inode, so we give it a fake inode value
(2) and intercept that inode on a getattr.

Fixes: #1957
Signed-off-by: Sam Lang <sam.lang@inktank.com>
src/client/Client.cc

index 396f1efe770ed6eac3d77401a52312c7ee7e1602..1e149e799fe1dcd5db35a129929e64a6b2a0fdb4 100644 (file)
@@ -4449,7 +4449,7 @@ int Client::readdir_r_cb(dir_result_t *d, add_dirent_cb_t cb, void *p)
   if (dirp->offset == 0) {
     ldout(cct, 15) << " including ." << dendl;
     assert(diri->dn_set.size() < 2); // can't have multiple hard-links to a dir
-    uint64_t next_off = (!diri->dn_set.empty()) ? 1 : 2;
+    uint64_t next_off = 1;
 
     fill_dirent(&de, ".", S_IFDIR, diri->ino, next_off);
 
@@ -4466,11 +4466,16 @@ int Client::readdir_r_cb(dir_result_t *d, add_dirent_cb_t cb, void *p)
   }
   if (dirp->offset == 1) {
     ldout(cct, 15) << " including .." << dendl;
-    assert(!diri->dn_set.empty());
-    Inode *in = diri->get_first_parent()->inode;
-    fill_dirent(&de, "..", S_IFDIR, in->ino, 2);
+    if (!diri->dn_set.empty()) {
+      Inode* in = diri->get_first_parent()->inode;
+      fill_dirent(&de, "..", S_IFDIR, in->ino, 2);
+      fill_stat(in, &st);
+    } else {
+      /* must be at the root (no parent),
+       * so we add the dotdot with a special inode (0) */
+      fill_dirent(&de, "..", S_IFDIR, 2, 2);
+    }
 
-    fill_stat(in, &st);
 
     client_lock.Unlock();
     int r = cb(p, &de, &st, -1, 2);
@@ -5851,6 +5856,13 @@ int Client::ll_getattr(vinodeno_t vino, struct stat *attr, int uid, int gid)
   tout(cct) << "ll_getattr" << std::endl;
   tout(cct) << vino.ino.val << std::endl;
 
+  /* special case for dotdot (..) */
+  if (vino.ino.val == 2) {
+    attr->st_mode = S_IFDIR | 0755;
+    attr->st_nlink = 2;
+    return 0;
+  }
+
   Inode *in = _ll_get_inode(vino);
   int res;
   if (vino.snapid < CEPH_NOSNAP)