]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: fix readder result merge
authorSage Weil <sage.weil@dreamhost.com>
Tue, 30 Aug 2011 14:09:06 +0000 (07:09 -0700)
committerSage Weil <sage.weil@dreamhost.com>
Tue, 30 Aug 2011 14:15:10 +0000 (07:15 -0700)
When merging readdir results into the cache, we want to remove any names
_preceeding_ the current item before updating it.  Then, at the end, we
clean up the trailing items.

This fixes a cfuse crash on workunits/snaps/snaptest-2.sh.

Signed-off-by: Sage Weil <sage.weil@dreamhost.com>
src/client/Client.cc

index ffdb0c7b87dfdd73d021d606e087d3b178a05e40..353c166d0a4128111d1fa24d56d8ae64d29519c8 100644 (file)
@@ -791,12 +791,13 @@ Inode* Client::insert_trace(MetaRequest *request, int mds)
     ::decode(complete, p);
     
     ldout(cct, 10) << "insert_trace " << numdn << " readdir items, end=" << (int)end
-            << ", offset " << request->readdir_offset << dendl;
+                  << ", offset " << request->readdir_offset
+                  << ", readdir_start " << request->readdir_start << dendl;
 
     request->readdir_end = end;
     request->readdir_num = numdn;
 
-    map<string,Dentry*>::iterator pd = dir->dentry_map.upper_bound(request->readdir_start);
+    map<string,Dentry*>::iterator pd = dir->dentry_map.lower_bound(request->readdir_start);
 
     frag_t fg = request->readdir_frag;
     Inode *diri = in;
@@ -808,6 +809,27 @@ Inode* Client::insert_trace(MetaRequest *request, int mds)
       ::decode(dlease, p);
       InodeStat ist(p, features);
 
+      ldout(cct, 15) << "" << i << ": '" << dname << "'" << dendl;
+
+      // remove any skipped names
+      while (pd != dir->dentry_map.end() && pd->first < dname) {
+       if (pd->first < dname &&
+           diri->dirfragtree[ceph_str_hash_linux(pd->first.c_str(),
+                                                 pd->first.length())] == fg) {  // do not remove items in earlier frags
+         ldout(cct, 15) << "insert_trace  unlink '" << pd->first << "'" << dendl;
+         Dentry *dn = pd->second;
+         pd++;
+         unlink(dn, true);
+       } else {
+         pd++;
+       }
+      }
+
+      if (pd == dir->dentry_map.end())
+       ldout(cct, 15) << " pd is at end" << dendl;
+      else
+       ldout(cct, 15) << " pd is '" << pd->first << "' dn " << pd->second << dendl;
+
       Inode *in = add_update_inode(&ist, request->sent_stamp, mds);
       Dentry *dn;
       if (pd != dir->dentry_map.end() &&
@@ -830,19 +852,6 @@ Inode* Client::insert_trace(MetaRequest *request, int mds)
       update_dentry_lease(dn, &dlease, request->sent_stamp, mds);
       dn->offset = dir_result_t::make_fpos(request->readdir_frag, i + request->readdir_offset);
 
-      // remove any extra names
-      while (pd != dir->dentry_map.end() && pd->first <= dname) {
-       if (pd->first < dname &&
-           diri->dirfragtree[ceph_str_hash_linux(pd->first.c_str(),
-                                                 pd->first.length())] == fg) {  // do not remove items in earlier frags
-         ldout(cct, 15) << "insert_trace  unlink '" << pd->first << "'" << dendl;
-         Dentry *dn = pd->second;
-         pd++;
-         unlink(dn, true);
-       } else
-         pd++;
-      }
-      
       // add to cached result list
       in->get();
       request->readdir_result.push_back(pair<string,Inode*>(dname, in));