]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: fix readdir + cap recovation/reissue race
authorSage Weil <sage@newdream.net>
Wed, 24 Aug 2011 21:38:25 +0000 (14:38 -0700)
committerSage Weil <sage@newdream.net>
Wed, 24 Aug 2011 21:38:25 +0000 (14:38 -0700)
The current race:
 - we start readdir
 - mds revokes dir cap
 - some file gets removed
 - mds reissues dir cap
 - we finish readdir and set I_COMPLETE

We should only set it if there have been no FILE_SHARED reissues during
the readdir.

Note that we still set I_COMPLETE even if we don't have the cap; that's
useless but harmless, since it is undefined without FILE_SHARED being
set.

Signed-off-by: Sage Weil <sage@newdream.net>
src/client/Client.cc
src/client/Client.h

index 208569d86374a422ab5a23c62991c067f93d9617..c24b501b918a7ad883adc5854f1bda4951f68a60 100644 (file)
@@ -100,7 +100,7 @@ void client_flush_set_callback(void *p, ObjectCacher::ObjectSet *oset)
 
 dir_result_t::dir_result_t(Inode *in)
   : inode(in), offset(0), next_offset(2),
-    release_count(0),
+    release_count(0), start_shared_gen(0),
     buffer(0) { 
   inode->get();
 }
@@ -4138,8 +4138,9 @@ int Client::_opendir(Inode *in, dir_result_t **dirpp, int uid, int gid)
   if (!in->is_dir())
     return -ENOTDIR;
   (*dirpp)->set_frag(in->dirfragtree[0]);
-  if(in->dir)
+  if (in->dir)
     (*dirpp)->release_count = in->dir->release_count;
+  (*dirpp)->start_shared_gen = in->shared_gen;
   ldout(cct, 10) << "_opendir " << in->ino << ", our cache says the first dirfrag is " << (*dirpp)->frag() << dendl;
   ldout(cct, 3) << "_opendir(" << in->ino << ") = " << 0 << " (" << *dirpp << ")" << dendl;
   return 0;
@@ -4516,7 +4517,9 @@ int Client::readdir_r_cb(dir_result_t *d, add_dirent_cb_t cb, void *p)
       continue;
     }
 
-    if (diri->dir && diri->dir->release_count == dirp->release_count) {
+    if (diri->dir &&
+       diri->dir->release_count == dirp->release_count &&
+       diri->shared_gen == dirp->start_shared_gen) {
       ldout(cct, 10) << " marking I_COMPLETE on " << *diri << dendl;
       diri->flags |= I_COMPLETE;
       if (diri->dir)
index bd7479617ffdfa9316d323c6aa468bdae4d9ab09..bfa077116ea8b01f95d8aa6207945a5fe1fae841 100644 (file)
@@ -145,6 +145,7 @@ struct dir_result_t {
   string last_name;      // last entry in previous chunk
 
   uint64_t release_count;
+  int start_shared_gen;  // dir shared_gen at start of readdir
 
   frag_t buffer_frag;
   vector<pair<string,Inode*> > *buffer;