[Pkg-ceph-commits] [ceph] 01/01: Patchworks

Dmitry Smirnov onlyjob at moszumanska.debian.org
Sat Nov 15 16:31:22 UTC 2014


This is an automated email from the git hooks/post-receive script.

onlyjob pushed a commit to branch experimental
in repository ceph.

commit 9a25bee (experimental)
Author: Dmitry Smirnov <onlyjob at member.fsf.org>
Date:   Sat Nov 15 16:30:18 2014

    Patchworks
---
 debian/patches/0latest-giant.patch | 955 +++++++++++++++++++++++++++++++++++++
 debian/patches/bug-10059.patch     |  28 ++
 debian/patches/bug-9341.patch      | 107 -----
 debian/patches/bug-9752.patch      |  33 --
 debian/patches/bug-9869.patch      |  40 --
 debian/patches/bug-9945.patch      |  50 --
 debian/patches/series              |   6 +-
 debian/patches/sleep-recover.patch |   2 +-
 8 files changed, 986 insertions(+), 235 deletions(-)

diff --git a/debian/patches/0latest-giant.patch b/debian/patches/0latest-giant.patch
new file mode 100644
index 0000000..251cb02
--- /dev/null
+++ b/debian/patches/0latest-giant.patch
@@ -0,0 +1,955 @@
+Last-Update: 2014-11-15
+Forwarded: not-needed
+Origin: upstream
+Author: Dmitry Smirnov <onlyjob at member.fsf.org>
+Description: fixes from "Giant" branch since 0.87 release
+
+--- a/src/client/Client.cc
++++ b/src/client/Client.cc
+@@ -141,9 +141,9 @@
+ // -------------
+ 
+ dir_result_t::dir_result_t(Inode *in)
+   : inode(in), offset(0), this_offset(2), next_offset(2),
+-    release_count(0), start_shared_gen(0),
++    release_count(0), ordered_count(0), start_shared_gen(0),
+     buffer(0) {
+   inode->get();
+ }
+ 
+@@ -505,17 +505,47 @@
+     inode_map.clear();
+   }
+ }
+ 
++void Client::trim_cache_for_reconnect(MetaSession *s)
++{
++  int mds = s->mds_num;
++  ldout(cct, 20) << "trim_cache_for_reconnect mds." << mds << dendl;
++
++  int trimmed = 0;
++  list<Dentry*> skipped;
++  while (lru.lru_get_size() > 0) {
++    Dentry *dn = static_cast<Dentry*>(lru.lru_expire());
++    if (!dn)
++      break;
++
++    if ((dn->inode && dn->inode->caps.count(mds)) ||
++	dn->dir->parent_inode->caps.count(mds)) {
++      trim_dentry(dn);
++      trimmed++;
++    } else
++      skipped.push_back(dn);
++  }
++
++  for(list<Dentry*>::iterator p = skipped.begin(); p != skipped.end(); ++p)
++    lru.lru_insert_mid(*p);
++
++  ldout(cct, 20) << "trim_cache_for_reconnect mds." << mds
++		 << " trimmed " << trimmed << " dentries" << dendl;
++
++  if (s->caps.size() > 0)
++    _invalidate_kernel_dcache();
++}
++
+ void Client::trim_dentry(Dentry *dn)
+ {
+   ldout(cct, 15) << "trim_dentry unlinking dn " << dn->name 
+ 		 << " in dir " << hex << dn->dir->parent_inode->ino 
+ 		 << dendl;
++  dn->dir->release_count++;
+   if (dn->dir->parent_inode->flags & I_COMPLETE) {
+-    ldout(cct, 10) << " clearing I_COMPLETE on " << *dn->dir->parent_inode << dendl;
+-    dn->dir->parent_inode->flags &= ~I_COMPLETE;
+-    dn->dir->release_count++;
++    ldout(cct, 10) << " clearing (I_COMPLETE|I_DIR_ORDERED) on " << *dn->dir->parent_inode << dendl;
++    dn->dir->parent_inode->flags &= ~(I_COMPLETE | I_DIR_ORDERED);
+   }
+   unlink(dn, false, false);  // drop dir, drop dentry
+ }
+ 
+@@ -734,19 +764,19 @@
+       (st->cap.caps & CEPH_CAP_FILE_SHARED) &&
+       (issued & CEPH_CAP_FILE_EXCL) == 0 &&
+       in->dirstat.nfiles == 0 &&
+       in->dirstat.nsubdirs == 0) {
+-    ldout(cct, 10) << " marking I_COMPLETE on empty dir " << *in << dendl;
+-    in->flags |= I_COMPLETE;
++    ldout(cct, 10) << " marking (I_COMPLETE|I_DIR_ORDERED) on empty dir " << *in << dendl;
++    in->flags |= I_COMPLETE | I_DIR_ORDERED;
+     if (in->dir) {
+       ldout(cct, 10) << " dir is open on empty dir " << in->ino << " with "
+-		     << in->dir->dentry_map.size() << " entries, marking all dentries null" << dendl;
+-      for (map<string, Dentry*>::iterator p = in->dir->dentry_map.begin();
+-	   p != in->dir->dentry_map.end();
++		     << in->dir->dentry_list.size() << " entries, marking all dentries null" << dendl;
++      for (xlist<Dentry*>::iterator p = in->dir->dentry_list.begin();
++	   !p.end();
+ 	   ++p) {
+-	unlink(p->second, true, true);  // keep dir, keep dentry
++	unlink(*p, true, true);  // keep dir, keep dentry
+       }
+-      if (in->dir->dentry_map.empty())
++      if (in->dir->dentry_list.empty())
+ 	close_dir(in->dir);
+     }
+   }
+ 
+@@ -757,9 +787,9 @@
+ /*
+  * insert_dentry_inode - insert + link a single dentry + inode into the metadata cache.
+  */
+ Dentry *Client::insert_dentry_inode(Dir *dir, const string& dname, LeaseStat *dlease, 
+-				    Inode *in, utime_t from, MetaSession *session, bool set_offset,
++				    Inode *in, utime_t from, MetaSession *session,
+ 				    Dentry *old_dentry)
+ {
+   Dentry *dn = NULL;
+   if (dir->dentries.count(dname))
+@@ -784,16 +814,26 @@
+   }
+   
+   if (!dn || dn->inode == 0) {
+     in->get();
+-    if (old_dentry)
++    if (old_dentry) {
++      if (old_dentry->dir != dir) {
++	old_dentry->dir->ordered_count++;
++	if (old_dentry->dir->parent_inode->flags & I_DIR_ORDERED) {
++	  ldout(cct, 10) << " clearing I_DIR_ORDERED on "
++			 << *old_dentry->dir->parent_inode << dendl;
++	  old_dentry->dir->parent_inode->flags &= ~I_DIR_ORDERED;
++	}
++      }
+       unlink(old_dentry, dir == old_dentry->dir, false);  // drop dentry, keep dir open if its the same dir
++    }
++    dir->ordered_count++;
++    if (dir->parent_inode->flags & I_DIR_ORDERED) {
++	ldout(cct, 10) << " clearing I_DIR_ORDERED on " << *dir->parent_inode << dendl;
++	dir->parent_inode->flags &= ~I_DIR_ORDERED;
++    }
+     dn = link(dir, dname, in, dn);
+     put_inode(in);
+-    if (set_offset) {
+-      ldout(cct, 15) << " setting dn offset to " << dir->max_offset << dendl;
+-      dn->offset = dir->max_offset++;
+-    }
+   }
+ 
+   update_dentry_lease(dn, dlease, from, session);
+   return dn;
+@@ -907,10 +947,8 @@
+     request->readdir_reply_frag = fg;
+     request->readdir_end = end;
+     request->readdir_num = numdn;
+ 
+-    map<string,Dentry*>::iterator pd = dir->dentry_map.upper_bound(readdir_start);
+-
+     string dname;
+     LeaseStat dlease;
+     for (unsigned i=0; i<numdn; i++) {
+       ::decode(dname, p);
+@@ -918,46 +956,22 @@
+       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 &&
+-	    fg.contains(diri->hash_dentry_name(pd->first))) {  // do not remove items in earlier frags
+-	  Dentry *dn = pd->second;
+-	  if (dn->inode) {
+-	    ldout(cct, 15) << __func__ << "  unlink '" << pd->first << "'" << dendl;
+-	    ++pd;
+-	    unlink(dn, true, true);  // keep dir, dentry
+-	  } else {
+-	    ++pd;
+-	  }
+-	} 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, session);
+       Dentry *dn;
+-      if (pd != dir->dentry_map.end() &&
+-	  pd->first == dname) {
+-	Dentry *olddn = pd->second;
+-	if (pd->second->inode != in) {
++      if (diri->dir->dentries.count(dname)) {
++	Dentry *olddn = diri->dir->dentries[dname];
++	if (olddn->inode != in) {
+ 	  // replace incorrect dentry
+-	  ++pd;  // we are about to unlink this guy, move past it.
+ 	  unlink(olddn, true, true);  // keep dir, dentry
+ 	  dn = link(dir, dname, in, olddn);
+ 	  assert(dn == olddn);
+ 	} else {
+ 	  // keep existing dn
+ 	  dn = olddn;
+ 	  touch_dn(dn);
+-	  ++pd;  // move past the dentry we just touched.
++	  dn->item_dentry_list.move_to_back();
+ 	}
+       } else {
+ 	// new dn
+ 	dn = link(dir, dname, in, NULL);
+@@ -972,21 +986,8 @@
+       ldout(cct, 15) << __func__ << "  " << hex << dn->offset << dec << ": '" << dname << "' -> " << in->ino << dendl;
+     }
+     request->readdir_last_name = dname;
+ 
+-    // remove trailing names
+-    if (end) {
+-      while (pd != dir->dentry_map.end()) {
+-	if (fg.contains(diri->hash_dentry_name(pd->first))) {
+-	  ldout(cct, 15) << __func__ << "  unlink '" << pd->first << "'" << dendl;
+-	  Dentry *dn = pd->second;
+-	  ++pd;
+-	  unlink(dn, true, true); // keep dir, dentry
+-	} else
+-	  ++pd;
+-      }
+-    }
+-
+     if (dir->is_empty())
+       close_dir(dir);
+   }
+ }
+@@ -1014,13 +1015,14 @@
+   if (p.end()) {
+     ldout(cct, 10) << "insert_trace -- no trace" << dendl;
+ 
+     Dentry *d = request->dentry();
+-    if (d && d->dir &&
+-	(d->dir->parent_inode->flags & I_COMPLETE)) {
+-      ldout(cct, 10) << " clearing I_COMPLETE on " << *d->dir->parent_inode << dendl;
+-      d->dir->parent_inode->flags &= ~I_COMPLETE;
++    if (d && d->dir) {
+       d->dir->release_count++;
++      if (d->dir->parent_inode->flags & I_COMPLETE) {
++	ldout(cct, 10) << " clearing (I_COMPLETE|I_DIR_ORDERED) on " << *d->dir->parent_inode << dendl;
++	d->dir->parent_inode->flags &= ~(I_COMPLETE | I_DIR_ORDERED);
++      }
+     }
+ 
+     if (d && reply->get_result() == 0) {
+       if (request->head.op == CEPH_MDS_OP_RENAME) {
+@@ -1077,16 +1079,22 @@
+     update_dir_dist(diri, &dst);  // dir stat info is attached to ..
+ 
+     if (in) {
+       Dir *dir = diri->open_dir();
+-      insert_dentry_inode(dir, dname, &dlease, in, request->sent_stamp, session, true,
++      insert_dentry_inode(dir, dname, &dlease, in, request->sent_stamp, session,
+                           ((request->head.op == CEPH_MDS_OP_RENAME) ?
+                                         request->old_dentry() : NULL));
+     } else {
+       if (diri->dir && diri->dir->dentries.count(dname)) {
+ 	Dentry *dn = diri->dir->dentries[dname];
+-	if (dn->inode)
++	if (dn->inode) {
++	  diri->dir->ordered_count++;
++	  if (diri->flags & I_DIR_ORDERED) {
++	    ldout(cct, 10) << " clearing I_DIR_ORDERED on " << *diri << dendl;
++	    diri->flags &= ~I_DIR_ORDERED;
++	  }
+ 	  unlink(dn, true, true);  // keep dir, dentry
++	}
+       }
+     }
+   } else if (reply->head.op == CEPH_MDS_OP_LOOKUPSNAP ||
+ 	     reply->head.op == CEPH_MDS_OP_MKSNAP) {
+@@ -1103,9 +1111,9 @@
+     dlease.duration_ms = 0;
+ 
+     if (in) {
+       Dir *dir = diri->open_dir();
+-      insert_dentry_inode(dir, dname, &dlease, in, request->sent_stamp, session, true);
++      insert_dentry_inode(dir, dname, &dlease, in, request->sent_stamp, session);
+     } else {
+       if (diri->dir && diri->dir->dentries.count(dname)) {
+ 	Dentry *dn = diri->dir->dentries[dname];
+ 	if (dn->inode)
+@@ -2051,10 +2059,15 @@
+     int newstate = mdsmap->get_state(p->first);
+     if (!mdsmap->is_up(p->first) ||
+ 	mdsmap->get_inst(p->first) != p->second->inst) {
+       p->second->con->mark_down();
+-      if (mdsmap->is_up(p->first))
++      if (mdsmap->is_up(p->first)) {
+ 	p->second->inst = mdsmap->get_inst(p->first);
++	// When new MDS starts to take over, notify kernel to trim unused entries
++	// in its dcache/icache. Hopefully, the kernel will release some unused
++	// inodes before the new MDS enters reconnect state.
++	trim_cache_for_reconnect(p->second);
++      }
+     } else if (oldstate == newstate)
+       continue;  // no change
+     
+     if (newstate == MDSMap::STATE_RECONNECT &&
+@@ -2090,8 +2103,16 @@
+ {
+   int mds = session->mds_num;
+   ldout(cct, 10) << "send_reconnect to mds." << mds << dendl;
+ 
++  // trim unused caps to reduce MDS's cache rejoin time
++  trim_cache_for_reconnect(session);
++
++  if (session->release) {
++    session->release->put();
++    session->release = NULL;
++  }
++
+   MClientReconnect *m = new MClientReconnect;
+ 
+   // i have an open session.
+   ceph::unordered_set<inodeno_t> did_snaprealm;
+@@ -2295,16 +2316,17 @@
+     
+     // link to dir
+     dn->dir = dir;
+     dir->dentries[dn->name] = dn;
+-    dir->dentry_map[dn->name] = dn;
++    dir->dentry_list.push_back(&dn->item_dentry_list);
+     lru.lru_insert_mid(dn);    // mid or top?
+ 
+     ldout(cct, 15) << "link dir " << dir->parent_inode << " '" << name << "' to inode " << in
+ 		   << " dn " << dn << " (new dn)" << dendl;
+   } else {
+     ldout(cct, 15) << "link dir " << dir->parent_inode << " '" << name << "' to inode " << in
+ 		   << " dn " << dn << " (old dn)" << dendl;
++    dn->item_dentry_list.move_to_back();
+   }
+ 
+   if (in) {    // link to inode
+     dn->inode = in;
+@@ -2360,9 +2382,9 @@
+     ldout(cct, 15) << "unlink  removing '" << dn->name << "' dn " << dn << dendl;
+ 
+     // unlink from dir
+     dn->dir->dentries.erase(dn->name);
+-    dn->dir->dentry_map.erase(dn->name);
++    dn->item_dentry_list.remove_myself();
+     if (dn->dir->is_empty() && !keepdir)
+       close_dir(dn->dir);
+     dn->dir = 0;
+ 
+@@ -2514,13 +2536,25 @@
+ 	   << " dropping " << ccap_string(dropping)
+ 	   << dendl;
+ 
+   if (cct->_conf->client_inject_release_failure && revoking) {
++    const int would_have_issued = cap->issued & retain;
++    const int would_have_implemented = cap->implemented & (cap->issued | used);
+     // Simulated bug:
+     //  - tell the server we think issued is whatever they issued plus whatever we implemented
+     //  - leave what we have implemented in place
+     ldout(cct, 20) << __func__ << " injecting failure to release caps" << dendl;
+     cap->issued = cap->issued | cap->implemented;
++
++    // Make an exception for revoking xattr caps: we are injecting
++    // failure to release other caps, but allow xattr because client
++    // will block on xattr ops if it can't release these to MDS (#9800)
++    const int xattr_mask = CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL;
++    cap->issued ^= xattr_mask & revoking;
++    cap->implemented ^= xattr_mask & revoking;
++
++    ldout(cct, 20) << __func__ << " issued " << ccap_string(cap->issued) << " vs " << ccap_string(would_have_issued) << dendl;
++    ldout(cct, 20) << __func__ << " implemented " << ccap_string(cap->implemented) << " vs " << ccap_string(would_have_implemented) << dendl;
+   } else {
+     // Normal behaviour
+     cap->issued &= retain;
+     cap->implemented &= cap->issued | used;
+@@ -3028,10 +3062,10 @@
+       !(had & CEPH_CAP_FILE_SHARED)) {
+     in->shared_gen++;
+ 
+     if (in->is_dir() && (in->flags & I_COMPLETE)) {
+-      ldout(cct, 10) << " clearing I_COMPLETE on " << *in << dendl;
+-      in->flags &= ~I_COMPLETE;
++      ldout(cct, 10) << " clearing (I_COMPLETE|I_DIR_ORDERED) on " << *in << dendl;
++      in->flags &= ~(I_COMPLETE | I_DIR_ORDERED);
+     }
+   }
+ }
+ 
+@@ -3195,8 +3229,22 @@
+   }
+   sync_cond.Signal();
+ }
+ 
++void Client::_invalidate_kernel_dcache()
++{
++  // notify kernel to invalidate top level directory entries. As a side effect,
++  // unused inodes underneath these entries get pruned.
++  if (dentry_invalidate_cb && root->dir) {
++    for (ceph::unordered_map<string, Dentry*>::iterator p = root->dir->dentries.begin();
++	 p != root->dir->dentries.end();
++	 ++p) {
++      if (p->second->inode)
++	_schedule_invalidate_dentry_callback(p->second, false);
++    }
++  }
++}
++
+ void Client::trim_caps(MetaSession *s, int max)
+ {
+   int mds = s->mds_num;
+   ldout(cct, 10) << "trim_caps mds." << mds << " max " << max << dendl;
+@@ -3253,25 +3301,10 @@
+     }
+   }
+   s->s_cap_iterator = NULL;
+ 
+-
+-  // notify kernel to invalidate top level directory entries. As a side effect,
+-  // unused inodes underneath these entries get pruned.
+-  if (dentry_invalidate_cb && s->caps.size() > max) {
+-    assert(root);
+-    if (root->dir) {
+-      for (ceph::unordered_map<string, Dentry*>::iterator p = root->dir->dentries.begin();
+-           p != root->dir->dentries.end();
+-           ++p) {
+-        if (p->second->inode)
+-          _schedule_invalidate_dentry_callback(p->second, false);
+-      }
+-    } else {
+-      // This seems unnatural, as long as we are holding caps they must be on
+-      // some descendent of the root, so why don't we have the root open?
+-    }
+-  }
++  if (s->caps.size() > max)
++    _invalidate_kernel_dcache();
+ }
+ 
+ void Client::mark_caps_dirty(Inode *in, int caps)
+ {
+@@ -3793,11 +3826,12 @@
+ {
+   int mds = session->mds_num;
+   int dirty = m->get_dirty();
+   int cleaned = 0;
++  uint16_t flush_ack_tid = static_cast<uint16_t>(m->get_client_tid());
+   for (int i = 0; i < CEPH_CAP_BITS; ++i) {
+     if ((dirty & (1 << i)) &&
+-	(m->get_client_tid() == in->flushing_cap_tid[i]))
++	(flush_ack_tid == in->flushing_cap_tid[i]))
+       cleaned |= 1 << i;
+   }
+ 
+   ldout(cct, 5) << "handle_cap_flush_ack mds." << mds
+@@ -5175,10 +5209,12 @@
+   if (!in->is_dir())
+     return -ENOTDIR;
+   *dirpp = new dir_result_t(in);
+   (*dirpp)->set_frag(in->dirfragtree[0]);
+-  if (in->dir)
++  if (in->dir) {
+     (*dirpp)->release_count = in->dir->release_count;
++    (*dirpp)->ordered_count = in->dir->ordered_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;
+@@ -5405,35 +5441,40 @@
+     dirp->set_end();
+     return 0;
+   }
+ 
+-  map<string,Dentry*>::iterator pd;
++  xlist<Dentry*>::iterator pd = dir->dentry_list.begin();
+   if (dirp->at_cache_name.length()) {
+-    pd = dir->dentry_map.find(dirp->at_cache_name);
+-    if (pd == dir->dentry_map.end())
+-      return -EAGAIN;  // weird, i give up
++    ceph::unordered_map<string,Dentry*>::iterator it = dir->dentries.find(dirp->at_cache_name);
++    if (it == dir->dentries.end())
++      return -EAGAIN;
++    Dentry *dn = it->second;
++    pd = xlist<Dentry*>::iterator(&dn->item_dentry_list);
+     ++pd;
+-  } else {
+-    pd = dir->dentry_map.begin();
+   }
+ 
+   string prev_name;
+-  while (pd != dir->dentry_map.end()) {
+-    Dentry *dn = pd->second;
++  while (!pd.end()) {
++    Dentry *dn = *pd;
+     if (dn->inode == NULL) {
+-      ldout(cct, 15) << " skipping null '" << pd->first << "'" << dendl;
++      ldout(cct, 15) << " skipping null '" << dn->name << "'" << dendl;
++      ++pd;
++      continue;
++    }
++    if (dn->cap_shared_gen != dir->parent_inode->shared_gen) {
++      ldout(cct, 15) << " skipping mismatch shared gen '" << dn->name << "'" << dendl;
+       ++pd;
+       continue;
+     }
+ 
+     struct stat st;
+     struct dirent de;
+     int stmask = fill_stat(dn->inode, &st);  
+-    fill_dirent(&de, pd->first.c_str(), st.st_mode, st.st_ino, dirp->offset + 1);
++    fill_dirent(&de, dn->name.c_str(), st.st_mode, st.st_ino, dirp->offset + 1);
+       
+     uint64_t next_off = dn->offset + 1;
+     ++pd;
+-    if (pd == dir->dentry_map.end())
++    if (pd.end())
+       next_off = dir_result_t::END;
+ 
+     client_lock.Unlock();
+     int r = cb(p, &de, &st, stmask, next_off);  // _next_ offset
+@@ -5528,14 +5569,15 @@
+   }
+ 
+   // can we read from our cache?
+   ldout(cct, 10) << "offset " << hex << dirp->offset << dec << " at_cache_name " << dirp->at_cache_name
+-	   << " snapid " << dirp->inode->snapid << " complete " << (bool)(dirp->inode->flags & I_COMPLETE)
++	   << " snapid " << dirp->inode->snapid << " (complete && ordered) "
++	   << dirp->inode->is_complete_and_ordered()
+ 	   << " issued " << ccap_string(dirp->inode->caps_issued())
+ 	   << dendl;
+   if ((dirp->offset == 2 || dirp->at_cache_name.length()) &&
+       dirp->inode->snapid != CEPH_SNAPDIR &&
+-      (dirp->inode->flags & I_COMPLETE) &&
++      dirp->inode->is_complete_and_ordered() &&
+       dirp->inode->caps_issued_mask(CEPH_CAP_FILE_SHARED)) {
+     int err = _readdir_cache_cb(dirp, cb, p);
+     if (err != -EAGAIN)
+       return err;
+@@ -5600,14 +5642,17 @@
+       continue;
+     }
+ 
+     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)
+-	diri->dir->max_offset = dirp->offset;
++	diri->shared_gen == dirp->start_shared_gen &&
++	diri->dir->release_count == dirp->release_count) {
++      if (diri->dir->ordered_count == dirp->ordered_count) {
++	ldout(cct, 10) << " marking (I_COMPLETE|I_DIR_ORDERED) on " << *diri << dendl;
++	diri->flags |= I_COMPLETE | I_DIR_ORDERED;
++      } else {
++	ldout(cct, 10) << " marking I_COMPLETE on " << *diri << dendl;
++	diri->flags |= I_COMPLETE;
++      }
+     }
+ 
+     dirp->set_end();
+     return 0;
+--- a/src/client/Client.h
++++ b/src/client/Client.h
+@@ -154,8 +154,9 @@
+   uint64_t next_offset;  // offset of next chunk (last_name's + 1)
+   string last_name;      // last entry in previous chunk
+ 
+   uint64_t release_count;
++  uint64_t ordered_count;
+   int start_shared_gen;  // dir shared_gen at start of readdir
+ 
+   frag_t buffer_frag;
+   vector<pair<string,Inode*> > *buffer;
+@@ -400,10 +401,12 @@
+   void touch_dn(Dentry *dn);
+ 
+   // trim cache.
+   void trim_cache();
++  void trim_cache_for_reconnect(MetaSession *s);
+   void trim_dentry(Dentry *dn);
+   void trim_caps(MetaSession *s, int max);
++  void _invalidate_kernel_dcache();
+   
+   void dump_inode(Formatter *f, Inode *in, set<Inode*>& did, bool disconnected);
+   void dump_cache(Formatter *f);  // debug
+   
+@@ -533,9 +536,9 @@
+ 			      version_t inline_version, bufferlist& inline_data,
+ 			      int issued);
+   Inode *add_update_inode(InodeStat *st, utime_t ttl, MetaSession *session);
+   Dentry *insert_dentry_inode(Dir *dir, const string& dname, LeaseStat *dlease, 
+-			      Inode *in, utime_t from, MetaSession *session, bool set_offset,
++			      Inode *in, utime_t from, MetaSession *session,
+ 			      Dentry *old_dentry = NULL);
+   void update_dentry_lease(Dentry *dn, LeaseStat *dlease, utime_t from, MetaSession *session);
+ 
+ 
+--- a/src/client/Dentry.h
++++ b/src/client/Dentry.h
+@@ -1,8 +1,9 @@
+ #ifndef CEPH_CLIENT_DENTRY_H
+ #define CEPH_CLIENT_DENTRY_H
+ 
+ #include "include/lru.h"
++#include "include/xlist.h"
+ 
+ class Dir;
+ struct Inode;
+ 
+@@ -19,8 +20,10 @@
+   uint64_t lease_gen;
+   ceph_seq_t lease_seq;
+   int cap_shared_gen;
+ 
++  xlist<Dentry*>::item item_dentry_list;
++
+   /*
+    * ref==1 -> cached, unused
+    * ref >1 -> pinned in lru
+    */
+@@ -40,9 +43,12 @@
+   }
+ 
+   void dump(Formatter *f) const;
+ 
+-  Dentry() : dir(0), inode(0), ref(1), offset(0), lease_mds(-1), lease_gen(0), lease_seq(0), cap_shared_gen(0) { }
++  Dentry() :
++    dir(0), inode(0), ref(1), offset(0),
++    lease_mds(-1), lease_gen(0), lease_seq(0), cap_shared_gen(0),
++    item_dentry_list(this)  { }
+ private:
+   ~Dentry() {
+     assert(ref == 0);
+   }
+--- a/src/client/Dir.h
++++ b/src/client/Dir.h
+@@ -6,13 +6,13 @@
+ class Dir {
+  public:
+   Inode    *parent_inode;  // my inode
+   ceph::unordered_map<string, Dentry*> dentries;
+-  map<string, Dentry*> dentry_map;
++  xlist<Dentry*> dentry_list;
+   uint64_t release_count;
+-  uint64_t max_offset;
++  uint64_t ordered_count;
+ 
+-  Dir(Inode* in) : release_count(0), max_offset(2) { parent_inode = in; }
++  Dir(Inode* in) : release_count(0), ordered_count(0) { parent_inode = in; }
+ 
+   bool is_empty() {  return dentries.empty(); }
+ };
+ 
+--- a/src/client/Inode.h
++++ b/src/client/Inode.h
+@@ -69,8 +69,9 @@
+ 
+ 
+ // inode flags
+ #define I_COMPLETE 1
++#define I_DIR_ORDERED 2
+ 
+ struct Inode {
+   CephContext *cct;
+ 
+@@ -133,8 +134,13 @@
+   }
+ 
+   unsigned flags;
+ 
++  bool is_complete_and_ordered() {
++    static const unsigned wants = I_COMPLETE | I_DIR_ORDERED;
++    return (flags & wants) == wants;
++  }
++
+   // about the dir (if this is one!)
+   set<int>  dir_contacts;
+   bool      dir_hashed, dir_replicated;
+ 
+--- a/src/common/config.cc
++++ b/src/common/config.cc
+@@ -946,9 +946,9 @@
+   return -ENOSYS;
+ }
+ 
+ static const char *CONF_METAVARIABLES[] =
+-  { "cluster", "type", "name", "host", "num", "id", "pid" };
++  { "cluster", "type", "name", "host", "num", "id", "pid", "cctid" };
+ static const int NUM_CONF_METAVARIABLES =
+       (sizeof(CONF_METAVARIABLES) / sizeof(CONF_METAVARIABLES[0]));
+ 
+ void md_config_t::expand_all_meta()
+@@ -1058,8 +1058,10 @@
+ 	else if (var == "id")
+ 	  out += name.get_id().c_str();
+ 	else if (var == "pid")
+ 	  out += stringify(getpid());
++	else if (var == "cctid")
++	  out += stringify((unsigned long long)this);
+ 	else
+ 	  assert(0); // unreachable
+ 	expanded = true;
+       }
+--- a/src/messages/MClientSession.h
++++ b/src/messages/MClientSession.h
+@@ -18,8 +18,9 @@
+ #include "msg/Message.h"
+ 
+ class MClientSession : public Message {
+   static const int HEAD_VERSION = 2;
++  static const int COMPAT_VERSION = 1;
+ 
+ public:
+   ceph_mds_session_head head;
+ 
+@@ -30,17 +31,17 @@
+   utime_t get_stamp() const { return utime_t(head.stamp); }
+   int get_max_caps() const { return head.max_caps; }
+   int get_max_leases() const { return head.max_leases; }
+ 
+-  MClientSession() : Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION) { }
++  MClientSession() : Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION, COMPAT_VERSION) { }
+   MClientSession(int o, version_t s=0) : 
+-    Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION) {
++    Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION, COMPAT_VERSION) {
+     memset(&head, 0, sizeof(head));
+     head.op = o;
+     head.seq = s;
+   }
+   MClientSession(int o, utime_t st) : 
+-    Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION) {
++    Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION, COMPAT_VERSION) {
+     memset(&head, 0, sizeof(head));
+     head.op = o;
+     head.seq = 0;
+     st.encode_timeval(&head.stamp);
+--- a/src/mon/Monitor.cc
++++ b/src/mon/Monitor.cc
+@@ -1582,8 +1582,10 @@
+  * @todo fix this. This is going to cause trouble.
+  */
+ void Monitor::handle_probe_probe(MMonProbe *m)
+ {
++  MMonProbe *r;
++
+   dout(10) << "handle_probe_probe " << m->get_source_inst() << *m
+ 	   << " features " << m->get_connection()->get_features() << dendl;
+   uint64_t missing = required_features & ~m->get_connection()->get_features();
+   if (missing) {
+@@ -1594,14 +1596,28 @@
+ 				   name, has_ever_joined);
+       m->required_features = required_features;
+       m->get_connection()->send_message(r);
+     }
+-    m->put();
+-    return;
++    goto out;
++  }
++
++  if (!is_probing() && !is_synchronizing()) {
++    // If the probing mon is way ahead of us, we need to re-bootstrap.
++    // Normally we capture this case when we initially bootstrap, but
++    // it is possible we pass those checks (we overlap with
++    // quorum-to-be) but fail to join a quorum before it moves past
++    // us.  We need to be kicked back to bootstrap so we can
++    // synchonize, not keep calling elections.
++    if (paxos->get_version() + 1 < m->paxos_first_version) {
++      dout(1) << " peer " << m->get_source_addr() << " has first_committed "
++	      << "ahead of us, re-bootstrapping" << dendl;
++      bootstrap();
++      goto out;
++
++    }
+   }
+ 
+-  MMonProbe *r = new MMonProbe(monmap->fsid, MMonProbe::OP_REPLY,
+-			       name, has_ever_joined);
++  r = new MMonProbe(monmap->fsid, MMonProbe::OP_REPLY, name, has_ever_joined);
+   r->name = name;
+   r->quorum = quorum;
+   monmap->encode(r->monmap_bl, m->get_connection()->get_features());
+   r->paxos_first_version = paxos->get_first_committed();
+@@ -1614,8 +1630,9 @@
+ 	    << " to list of hints" << dendl;
+     extra_probe_peers.insert(m->get_source_addr());
+   }
+ 
++ out:
+   m->put();
+ }
+ 
+ void Monitor::handle_probe_reply(MMonProbe *m)
+--- a/src/mon/Paxos.cc
++++ b/src/mon/Paxos.cc
+@@ -464,9 +464,9 @@
+   // commit and need to push it to them.
+   peer_first_committed[from] = last->first_committed;
+   peer_last_committed[from] = last->last_committed;
+ 
+-  if (last->first_committed > last_committed+1) {
++  if (last->first_committed > last_committed + 1) {
+     dout(5) << __func__
+             << " mon." << from
+ 	    << " lowest version is too high for our last committed"
+             << " (theirs: " << last->first_committed
+@@ -486,9 +486,9 @@
+   // is everyone contiguous and up to date?
+   for (map<int,version_t>::iterator p = peer_last_committed.begin();
+        p != peer_last_committed.end();
+        ++p) {
+-    if (p->second < first_committed && first_committed > 1) {
++    if (p->second + 1 < first_committed && first_committed > 1) {
+       dout(5) << __func__
+ 	      << " peon " << p->first
+ 	      << " last_committed (" << p->second
+ 	      << ") is too low for our first_committed (" << first_committed
+--- a/src/osd/OSD.cc
++++ b/src/osd/OSD.cc
+@@ -8094,10 +8094,10 @@
+ 
+   OSDMapRef send_map = service.try_get_map(m->get_map_epoch());
+   // check send epoch
+   if (!send_map) {
+-
+-    dout(7) << "don't have sender's osdmap; assuming it was valid and that client will resend" << dendl;
++    dout(7) << "don't have sender's osdmap; assuming it was valid and that"
++	    << " client will resend" << dendl;
+     return;
+   }
+   if (!send_map->have_pg_pool(pgid.pool())) {
+     dout(7) << "dropping request; pool did not exist" << dendl;
+@@ -8108,9 +8108,10 @@
+ 		      << ", client e" << m->get_map_epoch()
+ 		      << " when pool " << m->get_pg().pool() << " did not exist"
+ 		      << "\n";
+     return;
+-  } else if (send_map->get_pg_acting_role(pgid.pgid, whoami) < 0) {
++  }
++  if (!send_map->osd_is_valid_op_target(pgid.pgid, whoami)) {
+     dout(7) << "we are invalid target" << dendl;
+     clog->warn() << m->get_source_inst() << " misdirected " << m->get_reqid()
+ 		      << " pg " << m->get_pg()
+ 		      << " to osd." << whoami
+@@ -8124,10 +8125,11 @@
+   }
+ 
+   // check against current map too
+   if (!osdmap->have_pg_pool(pgid.pool()) ||
+-      osdmap->get_pg_acting_role(pgid.pgid, whoami) < 0) {
+-    dout(7) << "dropping; no longer have PG (or pool); client will retarget" << dendl;
++      !osdmap->osd_is_valid_op_target(pgid.pgid, whoami)) {
++    dout(7) << "dropping; no longer have PG (or pool); client will retarget"
++	    << dendl;
+     return;
+   }
+ 
+   PG *pg = get_pg_or_queue_for_pg(pgid, op);
+--- a/src/osd/OSDMap.h
++++ b/src/osd/OSDMap.h
+@@ -770,8 +770,20 @@
+     int nrep = pg_to_acting_osds(pg, group);
+     return calc_pg_role(osd, group, nrep);
+   }
+ 
++  bool osd_is_valid_op_target(pg_t pg, int osd) const {
++    int primary;
++    vector<int> group;
++    int nrep = pg_to_acting_osds(pg, &group, &primary);
++    if (osd == primary)
++      return true;
++    if (pg_is_ec(pg))
++      return false;
++
++    return calc_pg_role(osd, group, nrep) >= 0;
++  }
++
+ 
+   /*
+    * handy helpers to build simple maps...
+    */
+--- a/src/osd/osd_types.cc
++++ b/src/osd/osd_types.cc
+@@ -2302,11 +2302,11 @@
+   f->close_section();
+   f->open_array_section("acting");
+   for (vector<int>::const_iterator p = acting.begin(); p != acting.end(); ++p)
+     f->dump_int("osd", *p);
++  f->close_section();
+   f->dump_int("primary", primary);
+   f->dump_int("up_primary", up_primary);
+-  f->close_section();
+ }
+ 
+ void pg_interval_t::generate_test_instances(list<pg_interval_t*>& o)
+ {
+--- a/src/rgw/rgw_swift.cc
++++ b/src/rgw/rgw_swift.cc
+@@ -507,8 +507,10 @@
+     url.append(token);
+ 
+     validate.append_header("X-Auth-Token", admin_token);
+ 
++    validate.set_send_length(0);
++
+     int ret = validate.process(url.c_str());
+     if (ret < 0)
+       return ret;
+   }
+--- a/src/tools/cephfs/Dumper.cc
++++ b/src/tools/cephfs/Dumper.cc
+@@ -158,9 +158,9 @@
+ 
+   cout << "start " << start << " len " << len << std::endl;
+   
+   Journaler::Header h;
+-  h.trimmed_pos = start;
++  h.trimmed_pos = start - (start % g_default_file_layout.fl_object_size);
+   h.expire_pos = start;
+   h.write_pos = write_pos;
+   h.stream_format = format;
+   h.magic = CEPH_FS_ONDISK_MAGIC;
+--- a/src/tools/cephfs/JournalScanner.cc
++++ b/src/tools/cephfs/JournalScanner.cc
+@@ -153,12 +153,19 @@
+   bufferlist read_buf;
+   bool gap = false;
+   uint64_t gap_start = -1;
+   for (uint64_t obj_offset = (read_offset / object_size); ; obj_offset++) {
++    uint64_t offset_in_obj = 0;
++    if (obj_offset * object_size < header->expire_pos) {
++      // Skip up to expire_pos from start of the object
++      // (happens for the first object we read)
++      offset_in_obj = header->expire_pos - obj_offset * object_size;
++    }
++
+     // Read this journal segment
+     bufferlist this_object;
+     std::string const oid = obj_name(obj_offset);
+-    r = io.read(oid, this_object, INT_MAX, 0);
++    r = io.read(oid, this_object, INT_MAX, offset_in_obj);
+ 
+     // Handle absent journal segments
+     if (r < 0) {
+       if (obj_offset > (header->write_pos / object_size)) {
+--- a/src/tools/rados/rados.cc
++++ b/src/tools/rados/rados.cc
+@@ -430,12 +430,11 @@
+       cerr << "error reading input file " << infile << ": " << cpp_strerror(ret) << std::endl;
+       goto out;
+     }
+     if (count == 0) {
+-      if (!offset) {
+-	ret = io_ctx.create(oid, true);
++      if (!offset) { // in case we have to create an empty object
++	ret = io_ctx.write_full(oid, indata); // indata is empty
+ 	if (ret < 0) {
+-	  cerr << "WARNING: could not create object: " << oid << std::endl;
+ 	  goto out;
+ 	}
+       }
+       continue;
diff --git a/debian/patches/bug-10059.patch b/debian/patches/bug-10059.patch
new file mode 100644
index 0000000..9b28e1a
--- /dev/null
+++ b/debian/patches/bug-10059.patch
@@ -0,0 +1,28 @@
+commit c87bde6
+Author: Samuel Just <sjust at redhat.com>
+Date:   Sat Nov 15 10:44:20 2014
+
+    PG: always clear_primary_state when leaving Primary
+    
+    Otherwise, entries from the log collection process might leak into the next
+    epoch, where we might end up choosing a different authoritative log.  In this
+    case, it resulted in us not rolling back to log entries on one of the replicas
+    prior to trying to recover from an affected object due to the peer_missing not
+    being cleared.
+    
+    Fixes: #10059
+    Backport: giant, firefly, dumpling
+    Signed-off-by: Samuel Just <sjust at redhat.com>
+
+--- a/src/osd/PG.cc
++++ b/src/osd/PG.cc
+@@ -5533,8 +5533,9 @@
+   PG *pg = context< RecoveryMachine >().pg;
+   pg->want_acting.clear();
+   utime_t dur = ceph_clock_now(pg->cct) - enter_time;
+   pg->osd->recoverystate_perf->tinc(rs_primary_latency, dur);
++  pg->clear_primary_state();
+ }
+ 
+ /*---------Peering--------*/
+ PG::RecoveryState::Peering::Peering(my_context ctx)
diff --git a/debian/patches/bug-9341.patch b/debian/patches/bug-9341.patch
deleted file mode 100644
index 58e81ad..0000000
--- a/debian/patches/bug-9341.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-Last-update: 2014-10-20
-Forwarded: not-needed
-Origin: upstream, http://tracker.ceph.com/attachments/download/1388/0001-client-trim-unused-inodes-before-reconnecting-to-rec.patch
-Bug-Ceph: http://tracker.ceph.com/issues/9341
-From: Yan, Zheng <zyan at redhat.com>
-Description: dramatically (e.g seconds instead of hours) reduce rejoin (i.e. MDS restart) time.
-
---- a/src/client/Client.cc
-+++ b/src/client/Client.cc
-@@ -479,16 +479,21 @@
- 
- // ===================
- // metadata cache stuff
- 
--void Client::trim_cache()
-+void Client::trim_cache(unsigned max)
- {
--  ldout(cct, 20) << "trim_cache size " << lru.lru_get_size() << " max " << lru.lru_get_max() << dendl;
-+  if (max > lru.lru_get_max())
-+    max = lru.lru_get_max();
-+
-+  ldout(cct, 20) << "trim_cache size " << lru.lru_get_size() << " max " << max << dendl;
-+
-   unsigned last = 0;
-   while (lru.lru_get_size() != last) {
-     last = lru.lru_get_size();
- 
--    if (lru.lru_get_size() <= lru.lru_get_max())  break;
-+    if (lru.lru_get_size() <= max)
-+      break;
- 
-     // trim!
-     Dentry *dn = static_cast<Dentry*>(lru.lru_expire());
-     if (!dn)
-@@ -496,8 +501,24 @@
-     
-     trim_dentry(dn);
-   }
- 
-+  // notify kernel to invalidate top level directory entries. As a side effect,
-+  // unused inodes underneath these entries get pruned.
-+  if (dentry_invalidate_cb && lru.lru_get_size() > max) {
-+    if (root->dir) {
-+      for (ceph::unordered_map<string, Dentry*>::iterator p = root->dir->dentries.begin();
-+	  p != root->dir->dentries.end();
-+	  ++p) {
-+	if (p->second->inode)
-+	  _schedule_invalidate_dentry_callback(p->second, false);
-+      }
-+    } else {
-+      // This seems unnatural, as long as we are holding caps they must be on
-+      // some descendent of the root, so why don't we have the root open?`
-+    }
-+  }
-+
-   // hose root?
-   if (lru.lru_get_size() == 0 && root && root->get_num_ref() == 0 && inode_map.size() == 1) {
-     ldout(cct, 15) << "trim_cache trimmed root " << root << dendl;
-     delete root;
-@@ -2051,10 +2072,15 @@
-     int newstate = mdsmap->get_state(p->first);
-     if (!mdsmap->is_up(p->first) ||
- 	mdsmap->get_inst(p->first) != p->second->inst) {
-       p->second->con->mark_down();
--      if (mdsmap->is_up(p->first))
--	p->second->inst = mdsmap->get_inst(p->first);
-+      if (mdsmap->is_up(p->first)) {
-+ 	p->second->inst = mdsmap->get_inst(p->first);
-+	// When new MDS starts to take over, notify kernel to trim unused entries
-+	// in its dcache/icache. Hopefully, the kernel will release some unused
-+	// inodes before the new MDS enters reconnect state.
-+	trim_cache(1);
-+      }
-     } else if (oldstate == newstate)
-       continue;  // no change
-     
-     if (newstate == MDSMap::STATE_RECONNECT &&
-@@ -2090,8 +2116,16 @@
- {
-   int mds = session->mds_num;
-   ldout(cct, 10) << "send_reconnect to mds." << mds << dendl;
- 
-+  // trim unused caps to reduce MDS's cache rejoin time
-+  trim_cache(1);
-+
-+  if (session->release) {
-+    session->release->put();
-+    session->release = NULL;
-+  }
-+
-   MClientReconnect *m = new MClientReconnect;
- 
-   // i have an open session.
-   ceph::unordered_set<inodeno_t> did_snaprealm;
---- a/src/client/Client.h
-+++ b/src/client/Client.h
-@@ -399,9 +399,9 @@
-   int fill_stat(Inode *in, struct stat *st, frag_info_t *dirstat=0, nest_info_t *rstat=0);
-   void touch_dn(Dentry *dn);
- 
-   // trim cache.
--  void trim_cache();
-+  void trim_cache(unsigned max=-1U);
-   void trim_dentry(Dentry *dn);
-   void trim_caps(MetaSession *s, int max);
-   
-   void dump_inode(Formatter *f, Inode *in, set<Inode*>& did, bool disconnected);
diff --git a/debian/patches/bug-9752.patch b/debian/patches/bug-9752.patch
deleted file mode 100644
index 490bc29..0000000
--- a/debian/patches/bug-9752.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From e0b04414b92018277a0d3b9d82e72ea7529f4ef5 Mon Sep 17 00:00:00 2001
-From: Loic Dachary <loic-201408 at dachary.org>
-Date: Fri, 31 Oct 2014 00:49:21 +0100
-Subject: [PATCH] osd: past_interval display bug on acting
-
-The acting array was incorrectly including the primary and up_primary.
-
-http://tracker.ceph.com/issues/9752 Fixes: #9752
-
-Signed-off-by: Loic Dachary <loic-201408 at dachary.org>
-(cherry picked from commit c5f8d6eded52da451fdd1d807bd4700221e4c41c)
----
- src/osd/osd_types.cc | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/src/osd/osd_types.cc b/src/osd/osd_types.cc
-index ed06c4f..dc9caa5 100644
---- a/src/osd/osd_types.cc
-+++ b/src/osd/osd_types.cc
-@@ -2303,9 +2303,9 @@ void pg_interval_t::dump(Formatter *f) const
-   f->open_array_section("acting");
-   for (vector<int>::const_iterator p = acting.begin(); p != acting.end(); ++p)
-     f->dump_int("osd", *p);
-+  f->close_section();
-   f->dump_int("primary", primary);
-   f->dump_int("up_primary", up_primary);
--  f->close_section();
- }
- 
- void pg_interval_t::generate_test_instances(list<pg_interval_t*>& o)
--- 
-2.1.1
-
diff --git a/debian/patches/bug-9869.patch b/debian/patches/bug-9869.patch
deleted file mode 100644
index c2c4ae9..0000000
--- a/debian/patches/bug-9869.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From 905aba2f3d847933f98124f3ea8d1d76d644edb4 Mon Sep 17 00:00:00 2001
-From: Greg Farnum <greg at inktank.com>
-Date: Wed, 22 Oct 2014 17:16:31 -0700
-Subject: [PATCH] client: cast m->get_client_tid() to compare to 16-bit
- Inode::flushing_cap_tid
-
-m->get_client_tid() is 64 bits (as it should be), but Inode::flushing_cap_tid
-is only 16 bits. 16 bits should be plenty to let the cap flush updates
-pipeline appropriately, but we need to cast in the proper direction when
-comparing these differently-sized versions. So downcast the 64-bit one
-to 16 bits.
-
-Fixes: #9869
-Backport: giant, firefly, dumpling
-
-Signed-off-by: Greg Farnum <greg at inktank.com>
-(cherry picked from commit a5184cf46a6e867287e24aeb731634828467cd98)
----
- src/client/Client.cc | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/src/client/Client.cc b/src/client/Client.cc
-index 48e5400..ec3a232 100644
---- a/src/client/Client.cc
-+++ b/src/client/Client.cc
-@@ -3794,9 +3794,10 @@ void Client::handle_cap_flush_ack(MetaSession *session, Inode *in, Cap *cap, MCl
-   int mds = session->mds_num;
-   int dirty = m->get_dirty();
-   int cleaned = 0;
-+  uint16_t flush_ack_tid = static_cast<uint16_t>(m->get_client_tid());
-   for (int i = 0; i < CEPH_CAP_BITS; ++i) {
-     if ((dirty & (1 << i)) &&
--	(m->get_client_tid() == in->flushing_cap_tid[i]))
-+	(flush_ack_tid == in->flushing_cap_tid[i]))
-       cleaned |= 1 << i;
-   }
- 
--- 
-2.1.1
-
diff --git a/debian/patches/bug-9945.patch b/debian/patches/bug-9945.patch
deleted file mode 100644
index c9a75a3..0000000
--- a/debian/patches/bug-9945.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From b704f0dd888aacb10c32cdb63cdbf9f06296fc18 Mon Sep 17 00:00:00 2001
-From: John Spray <john.spray at redhat.com>
-Date: Thu, 30 Oct 2014 16:43:21 +0000
-Subject: [PATCH] messages: fix COMPAT_VERSION on MClientSession
-
-This was incorrectly incremented to 2 by omission
-of an explicit COMPAT_VERSION value.
-
-Fixes: #9945
-
-Signed-off-by: John Spray <john.spray at redhat.com>
-(cherry picked from commit 1eb9bcb1d36014293efc687b4331be8c4d208d8e)
----
- src/messages/MClientSession.h | 7 ++++---
- 1 file changed, 4 insertions(+), 3 deletions(-)
-
-diff --git a/src/messages/MClientSession.h b/src/messages/MClientSession.h
-index 0924189..3ef28e9 100644
---- a/src/messages/MClientSession.h
-+++ b/src/messages/MClientSession.h
-@@ -19,6 +19,7 @@
- 
- class MClientSession : public Message {
-   static const int HEAD_VERSION = 2;
-+  static const int COMPAT_VERSION = 1;
- 
- public:
-   ceph_mds_session_head head;
-@@ -31,15 +32,15 @@ public:
-   int get_max_caps() const { return head.max_caps; }
-   int get_max_leases() const { return head.max_leases; }
- 
--  MClientSession() : Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION) { }
-+  MClientSession() : Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION, COMPAT_VERSION) { }
-   MClientSession(int o, version_t s=0) : 
--    Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION) {
-+    Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION, COMPAT_VERSION) {
-     memset(&head, 0, sizeof(head));
-     head.op = o;
-     head.seq = s;
-   }
-   MClientSession(int o, utime_t st) : 
--    Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION) {
-+    Message(CEPH_MSG_CLIENT_SESSION, HEAD_VERSION, COMPAT_VERSION) {
-     memset(&head, 0, sizeof(head));
-     head.op = o;
-     head.seq = 0;
--- 
-2.1.1
-
diff --git a/debian/patches/series b/debian/patches/series
index 1f69b95..6f9791d 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,9 +1,7 @@
 ## Backported / Upstream
-bug-9341.patch
-bug-9752.patch
+0latest-giant.patch
 bug-9814.patch
-bug-9869.patch
-bug-9945.patch
+bug-10059.patch
 sleep-recover.patch
 
 ## Debian
diff --git a/debian/patches/sleep-recover.patch b/debian/patches/sleep-recover.patch
index e7c02d4..09865d1 100644
--- a/debian/patches/sleep-recover.patch
+++ b/debian/patches/sleep-recover.patch
@@ -6,7 +6,7 @@ Description: fix fuse-client hang after wake-up from suspend.
 
 --- a/src/client/Client.cc
 +++ b/src/client/Client.cc
-@@ -9359,8 +9359,9 @@
+@@ -9370,8 +9370,9 @@
  
  	case MetaSession::STATE_OPEN:
  	  ldout(cct, 1) << "reset from mds we were open; mark session as stale" << dendl;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ceph/ceph.git



More information about the Pkg-ceph-commits mailing list