]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
client: fix invalid iterator dereference in Client::trim_caps() 749/head
authorYan, Zheng <zheng.z.yan@intel.com>
Sun, 20 Oct 2013 09:08:42 +0000 (17:08 +0800)
committerYan, Zheng <zheng.z.yan@intel.com>
Sun, 20 Oct 2013 13:34:02 +0000 (21:34 +0800)
trimming inode drops a reference to the inode's parent, it may cause
the inode's parent also be trimmed. If the cap iterator 'p' happens to
point to the inode's parent and the inode's parent is trimmed, the cap
iterator 'p' become invalid.

Fix the issue by delaying removing cap from the seesion cap list.
(similar to what the kclient does)

Fixes #6599
Signed-off-by: Yan, Zheng <zheng.z.yan@intel.com>
src/client/Client.cc
src/client/MetaSession.h

index 20651892c0c4f1b4bd0792c79b77f53f07d81912..89de94ee6ea5bf75a19f86f7b48aca915d24eabd 100644 (file)
@@ -2921,8 +2921,6 @@ void Client::remove_cap(Cap *cap)
   i.seq = cap->issue_seq;
   i.migrate_seq = cap->mseq;
   session->release->caps.push_back(i);
-  
-  cap->cap_item.remove_myself();
 
   if (in->auth_cap == cap) {
     if (in->flushing_cap_item.is_on_list()) {
@@ -2933,7 +2931,13 @@ void Client::remove_cap(Cap *cap)
   }
   assert(in->caps.count(mds));
   in->caps.erase(mds);
-  delete cap;
+
+  if (cap == session->s_cap_iterator) {
+    cap->inode = NULL;
+  } else {
+    cap->cap_item.remove_myself();
+    delete cap;
+  }
 
   if (!in->is_any_caps()) {
     ldout(cct, 15) << "remove_cap last one, closing snaprealm " << in->snaprealm << dendl;
@@ -2966,7 +2970,7 @@ void Client::trim_caps(MetaSession *s, int max)
   xlist<Cap*>::iterator p = s->caps.begin();
   while (s->caps.size() > max && !p.end()) {
     Cap *cap = *p;
-    ++p;
+    s->s_cap_iterator = cap;
     Inode *in = cap->inode;
     if (in->caps.size() > 1 && cap != in->auth_cap) {
       // disposable non-auth cap
@@ -2992,7 +2996,14 @@ void Client::trim_caps(MetaSession *s, int max)
       if (all)
        trimmed++;
     }
+
+    ++p;
+    if (!cap->inode) {
+      cap->cap_item.remove_myself();
+      delete cap;
+    }
   }
+  s->s_cap_iterator = NULL;
 }
 
 void Client::mark_caps_dirty(Inode *in, int caps)
index a6cf634c9690193e057775b52633edb2000c3145..d9fcbb881d92682d1f2acd3ab393c7031f87cb6a 100644 (file)
@@ -43,12 +43,14 @@ struct MetaSession {
   xlist<MetaRequest*> requests;
   xlist<MetaRequest*> unsafe_requests;
 
+  Cap *s_cap_iterator;
+
   MClientCapRelease *release;
   
   MetaSession()
     : mds_num(-1), con(NULL),
       seq(0), cap_gen(0), cap_renew_seq(0), num_caps(0),
-      state(STATE_NEW),
+      state(STATE_NEW), s_cap_iterator(NULL),
       release(NULL)
   {}
   ~MetaSession();