]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: be careful about replacing dentries during readdir assimilation
authorSage Weil <sage@newdream.net>
Wed, 24 Aug 2011 23:51:15 +0000 (16:51 -0700)
committerSage Weil <sage@newdream.net>
Wed, 24 Aug 2011 23:51:15 +0000 (16:51 -0700)
When we are assimilate readdir results into our cache, we need to be more
careful about replacing existing dentries.  We were calling
insert_dentry_inode(), which would replace a name if it already exists,
which might include pd->first, an active iterator.

Move the dentry link/relink into the caller (where we already have an
iterator pointing to the existing item, if any).  Then update the dentry
lease information separately.

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

index 4c0cd2549f89c46452bec6ad3048306875a95799..bc7ed0366910554754a92f566cec95446cfce2c8 100644 (file)
@@ -808,9 +808,27 @@ Inode* Client::insert_trace(MetaRequest *request, utime_t from, int mds)
       ::decode(dname, p);
       ::decode(dlease, p);
       InodeStat ist(p, features);
-      
+
       Inode *in = add_update_inode(&ist, from, mds);
-      Dentry *dn = insert_dentry_inode(dir, dname, &dlease, in, from, mds, false);
+      Dentry *dn;
+      if (pd != dir->dentry_map.end() &&
+         pd->first == dname) {
+       Dentry *olddn = pd->second;
+       if (pd->second->inode != in) {
+         // replace incorrect dentry
+         pd++;
+         unlink(olddn, true);
+         dn = link(dir, dname, in, NULL);
+       } else {
+         // keep existing dn
+         dn = olddn;
+         touch_dn(dn);
+       }
+      } else {
+       // new dn
+       dn = link(dir, dname, in, NULL);
+      }
+      update_dentry_lease(dn, &dlease, from, mds);
       dn->offset = dir_result_t::make_fpos(request->readdir_frag, i + request->readdir_offset);
 
       // remove any extra names