[Pkg-ceph-commits] [ceph] 01/01: Imported Upstream version 0.80

Dmitry Smirnov onlyjob at moszumanska.debian.org
Wed May 7 07:18:29 UTC 2014


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

onlyjob pushed a commit to branch upstream
in repository ceph.

commit b905134 (upstream)
Author: Dmitry Smirnov <onlyjob at member.fsf.org>
Date:   Wed May 7 06:05:30 2014

    Imported Upstream version 0.80
---
 ceph.spec                 |   8 +-
 ceph.spec.in              |   8 +-
 configure                 |  22 ++--
 configure.ac              |   2 +-
 src/.git_version          |   4 +-
 src/client/Client.cc      |   8 +-
 src/include/rados.h       |   2 +
 src/mds/MDCache.cc        |  23 +++--
 src/mds/MDS.cc            |   7 +-
 src/mon/MonCommands.h     |   4 +-
 src/mon/OSDMonitor.cc     |  11 ++
 src/mon/PGMonitor.cc      |   1 +
 src/mount.fuse.ceph       |   3 +
 src/osd/ECBackend.cc      |   9 ++
 src/osd/OSD.cc            |   4 +-
 src/osd/PG.cc             |  18 +++-
 src/osd/PG.h              |  15 ++-
 src/osd/PGLog.h           |   4 +
 src/osd/ReplicatedPG.cc   | 254 +++++++++++++++++++++++++++-------------------
 src/osd/ReplicatedPG.h    |  20 +++-
 src/osd/osd_types.cc      |   1 +
 src/osd/osd_types.h       |   3 +-
 src/rgw/rgw_common.cc     |   2 +-
 src/test/librados/tier.cc |   4 +-
 24 files changed, 277 insertions(+), 160 deletions(-)

diff --git a/ceph.spec b/ceph.spec
index 207c94a..7105d13 100644
--- a/ceph.spec
+++ b/ceph.spec
@@ -9,13 +9,13 @@
 # common
 #################################################################################
 Name:		ceph
-Version:        0.80
-Release:        rc1%{?dist}
+Version:	0.80
+Release:	0%{?dist}
 Summary:	User space components of the Ceph file system
 License:	GPL-2.0
 Group:		System Environment/Base
 URL:		http://ceph.com/
-Source0:        http://ceph.com/download/%{name}-%{version}-rc1.tar.bz2
+Source0:	http://ceph.com/download/%{name}-%{version}.tar.bz2
 Requires:	librbd1 = %{version}-%{release}
 Requires:	librados2 = %{version}-%{release}
 Requires:	libcephfs1 = %{version}-%{release}
@@ -259,7 +259,7 @@ This package contains the Java libraries for the Ceph File System.
 # common
 #################################################################################
 %prep
-%setup -q -n %{name}-%{version}-rc1
+%setup -q
 
 %build
 # Find jni.h
diff --git a/ceph.spec.in b/ceph.spec.in
index 207c94a..ab30883 100644
--- a/ceph.spec.in
+++ b/ceph.spec.in
@@ -9,13 +9,13 @@
 # common
 #################################################################################
 Name:		ceph
-Version:        0.80
-Release:        rc1%{?dist}
+Version:	@VERSION@
+Release:	@RPM_RELEASE@%{?dist}
 Summary:	User space components of the Ceph file system
 License:	GPL-2.0
 Group:		System Environment/Base
 URL:		http://ceph.com/
-Source0:        http://ceph.com/download/%{name}-%{version}-rc1.tar.bz2
+Source0:	http://ceph.com/download/%{name}-%{version}.tar.bz2
 Requires:	librbd1 = %{version}-%{release}
 Requires:	librados2 = %{version}-%{release}
 Requires:	libcephfs1 = %{version}-%{release}
@@ -259,7 +259,7 @@ This package contains the Java libraries for the Ceph File System.
 # common
 #################################################################################
 %prep
-%setup -q -n %{name}-%{version}-rc1
+%setup -q
 
 %build
 # Find jni.h
diff --git a/configure b/configure
index 2f1b571..b882d94 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for ceph 0.80-rc1.
+# Generated by GNU Autoconf 2.68 for ceph 0.80.
 #
 # Report bugs to <ceph-devel at vger.kernel.org>.
 #
@@ -570,8 +570,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='ceph'
 PACKAGE_TARNAME='ceph'
-PACKAGE_VERSION='0.80-rc1'
-PACKAGE_STRING='ceph 0.80-rc1'
+PACKAGE_VERSION='0.80'
+PACKAGE_STRING='ceph 0.80'
 PACKAGE_BUGREPORT='ceph-devel at vger.kernel.org'
 PACKAGE_URL=''
 
@@ -1441,7 +1441,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures ceph 0.80-rc1 to adapt to many kinds of systems.
+\`configure' configures ceph 0.80 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1512,7 +1512,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of ceph 0.80-rc1:";;
+     short | recursive ) echo "Configuration of ceph 0.80:";;
    esac
   cat <<\_ACEOF
 
@@ -1657,7 +1657,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-ceph configure 0.80-rc1
+ceph configure 0.80
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2504,7 +2504,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by ceph $as_me 0.80-rc1, which was
+It was created by ceph $as_me 0.80, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -4504,7 +4504,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='ceph'
- VERSION='0.80-rc1'
+ VERSION='0.80'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -12482,7 +12482,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='ceph'
- VERSION='0.80-rc1'
+ VERSION='0.80'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -22258,7 +22258,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by ceph $as_me 0.80-rc1, which was
+This file was extended by ceph $as_me 0.80, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -22324,7 +22324,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-ceph config.status 0.80-rc1
+ceph config.status 0.80
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index e5b380f..f9482d6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,7 +8,7 @@ AC_PREREQ(2.59)
 # VERSION define is not used by the code.  It gets a version string
 # from 'git describe'; see src/ceph_ver.[ch]
 
-AC_INIT([ceph], [0.80-rc1], [ceph-devel at vger.kernel.org])
+AC_INIT([ceph], [0.80], [ceph-devel at vger.kernel.org])
 
 # Create release string.  Used with VERSION for RPMs.
 RPM_RELEASE=0
diff --git a/src/.git_version b/src/.git_version
index e0522fa..8e07215 100644
--- a/src/.git_version
+++ b/src/.git_version
@@ -1,2 +1,2 @@
-6769f4dc88425396921f94e1a37a1c90758aa3ea
-v0.80-rc1
+b78644e7dee100e48dfeca32c9270a6b210d3003
+v0.80
diff --git a/src/client/Client.cc b/src/client/Client.cc
index 5f750e6..03b6438 100644
--- a/src/client/Client.cc
+++ b/src/client/Client.cc
@@ -1464,7 +1464,7 @@ int Client::encode_inode_release(Inode *in, MetaRequest *req,
       rel.seq = caps->seq;
       rel.issue_seq = caps->issue_seq;
       rel.mseq = caps->mseq;
-      rel.caps = caps->issued;
+      rel.caps = caps->implemented;
       rel.wanted = caps->wanted;
       rel.dname_len = 0;
       rel.dname_seq = 0;
@@ -3574,9 +3574,11 @@ void Client::handle_cap_export(MetaSession *session, Inode *in, MClientCaps *m)
   ldout(cct, 5) << "handle_cap_export ino " << m->get_ino() << " mseq " << m->get_mseq()
 		<< " EXPORT from mds." << mds << dendl;
 
-  if (in->caps.count(mds)) {
-    Cap *cap = in->caps[mds];
+  Cap *cap = NULL;
+  if (in->caps.count(mds))
+    cap = in->caps[mds];
 
+  if (cap && cap->cap_id == m->get_cap_id()) {
     if (m->peer.cap_id) {
       MetaSession *tsession = _get_or_open_mds_session(m->peer.mds);
       if (in->caps.count(m->peer.mds)) {
diff --git a/src/include/rados.h b/src/include/rados.h
index 0d02b24..ba3d374 100644
--- a/src/include/rados.h
+++ b/src/include/rados.h
@@ -374,6 +374,8 @@ enum {
 	CEPH_OSD_FLAG_FLUSH =         0x40000,  /* this is part of flush */
 	CEPH_OSD_FLAG_MAP_SNAP_CLONE =0x80000,  /* map snap direct to clone id
 						 */
+	CEPH_OSD_FLAG_ENFORCE_SNAPC    =0x100000,  /* use snapc provided even if
+						      pool uses pool snaps */
 };
 
 enum {
diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc
index 49f3308..71a4b33 100644
--- a/src/mds/MDCache.cc
+++ b/src/mds/MDCache.cc
@@ -7289,17 +7289,12 @@ bool MDCache::shutdown_pass()
     return false;
   }
 
-  // make mydir subtree go away
-  if (myin) {
-    CDir *mydir = myin->get_dirfrag(frag_t());
-    if (mydir && mydir->is_subtree_root()) {
-      adjust_subtree_auth(mydir, CDIR_AUTH_UNKNOWN);
-      remove_subtree(mydir);
-    }
-  }
-  
+  CDir *mydir = myin ? myin->get_dirfrag(frag_t()) : NULL;
+  if (mydir && !mydir->is_subtree_root())
+    mydir = NULL;
+
   // subtrees map not empty yet?
-  if (!subtrees.empty()) {
+  if (subtrees.size() > (mydir ? 1 : 0)) {
     dout(7) << "still have " << num_subtrees() << " subtrees" << dendl;
     show_subtrees();
     migrator->show_importing();
@@ -7308,10 +7303,16 @@ bool MDCache::shutdown_pass()
       show_cache();
     return false;
   }
-  assert(subtrees.empty());
   assert(!migrator->is_exporting());
   assert(!migrator->is_importing());
 
+  // make mydir subtree go away
+  if (mydir) {
+    adjust_subtree_auth(mydir, CDIR_AUTH_UNKNOWN);
+    remove_subtree(mydir);
+  }
+  assert(subtrees.empty());
+
   // (only do this once!)
   if (!mds->mdlog->is_capped()) {
     dout(7) << "capping the log" << dendl;
diff --git a/src/mds/MDS.cc b/src/mds/MDS.cc
index 1d9015a..4509cea 100644
--- a/src/mds/MDS.cc
+++ b/src/mds/MDS.cc
@@ -1702,8 +1702,9 @@ void MDS::respawn()
   /* Determine the path to our executable, try to read
    * linux-specific /proc/ path first */
   char exe_path[PATH_MAX];
-  ssize_t exe_path_bytes = readlink("/proc/self/exe", exe_path, sizeof(exe_path));
-  if (exe_path_bytes == -1) {
+  ssize_t exe_path_bytes = readlink("/proc/self/exe", exe_path,
+				    sizeof(exe_path) - 1);
+  if (exe_path_bytes < 0) {
     /* Print CWD for the user's interest */
     char buf[PATH_MAX];
     char *cwd = getcwd(buf, sizeof(buf));
@@ -1712,6 +1713,8 @@ void MDS::respawn()
 
     /* Fall back to a best-effort: just running in our CWD */
     strncpy(exe_path, orig_argv[0], sizeof(exe_path) - 1);
+  } else {
+    exe_path[exe_path_bytes] = '\0';
   }
 
   dout(1) << " exe_path " << exe_path << dendl;
diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h
index 9fb83e2..36f1e9f 100644
--- a/src/mon/MonCommands.h
+++ b/src/mon/MonCommands.h
@@ -552,11 +552,11 @@ COMMAND("osd pool rename " \
 	"rename <srcpool> to <destpool>", "osd", "rw", "cli,rest")
 COMMAND("osd pool get " \
 	"name=pool,type=CephPoolname " \
-	"name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset|hit_set_type|hit_set_period|hit_set_count|hit_set_fpp", \
+	"name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset|hit_set_type|hit_set_period|hit_set_count|hit_set_fpp|auid", \
 	"get pool parameter <var>", "osd", "r", "cli,rest")
 COMMAND("osd pool set " \
 	"name=pool,type=CephPoolname " \
-	"name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset|hashpspool|hit_set_type|hit_set_period|hit_set_count|hit_set_fpp|debug_fake_ec_pool|target_max_bytes|target_max_objects|cache_target_dirty_ratio|cache_target_full_ratio|cache_min_flush_age|cache_min_evict_age " \
+	"name=var,type=CephChoices,strings=size|min_size|crash_replay_interval|pg_num|pgp_num|crush_ruleset|hashpspool|hit_set_type|hit_set_period|hit_set_count|hit_set_fpp|debug_fake_ec_pool|target_max_bytes|target_max_objects|cache_target_dirty_ratio|cache_target_full_ratio|cache_min_flush_age|cache_min_evict_age|auid " \
 	"name=val,type=CephString " \
 	"name=force,type=CephChoices,strings=--yes-i-really-mean-it,req=false", \
 	"set pool parameter <var> to <val>", "osd", "rw", "cli,rest")
diff --git a/src/mon/OSDMonitor.cc b/src/mon/OSDMonitor.cc
index fa3d9cf..dd027b2 100644
--- a/src/mon/OSDMonitor.cc
+++ b/src/mon/OSDMonitor.cc
@@ -1210,6 +1210,7 @@ bool OSDMonitor::preprocess_boot(MOSDBoot *m)
   if (osdmap.exists(from) &&
       osdmap.get_info(from).up_from > m->version) {
     dout(7) << "prepare_boot msg from before last up_from, ignoring" << dendl;
+    send_latest(m, m->sb.current_epoch+1);
     goto ignore;
   }
 
@@ -2457,6 +2458,8 @@ bool OSDMonitor::preprocess_command(MMonCommand *m)
         f->dump_int("pg_num", p->get_pg_num());
       } else if (var == "pgp_num") {
         f->dump_int("pgp_num", p->get_pgp_num());
+      } else if (var == "auid") {
+        f->dump_int("auid", p->get_auid());
       } else if (var == "size") {
         f->dump_int("size", p->get_size());
       } else if (var == "min_size") {
@@ -2490,6 +2493,8 @@ bool OSDMonitor::preprocess_command(MMonCommand *m)
         ss << "pg_num: " << p->get_pg_num();
       } else if (var == "pgp_num") {
         ss << "pgp_num: " << p->get_pgp_num();
+      } else if (var == "auid") {
+        ss << "auid: " << p->get_auid();
       } else if (var == "size") {
         ss << "size: " << p->get_size();
       } else if (var == "min_size") {
@@ -3330,6 +3335,12 @@ int OSDMonitor::prepare_command_pool_set(map<string,cmd_vartype> &cmdmap,
       return -EINVAL;
     }
     p.min_size = n;
+  } else if (var == "auid") {
+    if (interr.length()) {
+      ss << "error parsing integer value '" << val << "': " << interr;
+      return -EINVAL;
+    }
+    p.auid = n;
   } else if (var == "crash_replay_interval") {
     if (interr.length()) {
       ss << "error parsing integer value '" << val << "': " << interr;
diff --git a/src/mon/PGMonitor.cc b/src/mon/PGMonitor.cc
index fdee216..ae8f6e7 100644
--- a/src/mon/PGMonitor.cc
+++ b/src/mon/PGMonitor.cc
@@ -762,6 +762,7 @@ bool PGMonitor::prepare_pg_stats(MPGStats *stats)
   if (!pg_stats_have_changed(from, stats)) {
     dout(10) << " message contains no new osd|pg stats" << dendl;
     MPGStatsAck *ack = new MPGStatsAck;
+    ack->set_tid(stats->get_tid());
     for (map<pg_t,pg_stat_t>::const_iterator p = stats->pg_stat.begin();
 	 p != stats->pg_stat.end();
 	 ++p) {
diff --git a/src/mount.fuse.ceph b/src/mount.fuse.ceph
index cbf2874..785df6c 100755
--- a/src/mount.fuse.ceph
+++ b/src/mount.fuse.ceph
@@ -22,5 +22,8 @@ cephargs='--'`echo $1 | sed 's/,/ --/g'`
 # strip out 'noauto' option; libfuse doesn't like it
 opts=`echo $4 | sed 's/,noauto//' | sed 's/noauto,//'`
 
+# strip out '_netdev' option; libfuse doesn't like it
+opts=`echo $opts | sed 's/,_netdev//' | sed 's/_netdev,//'`
+
 # go
 exec ceph-fuse $cephargs $2 $3 $opts
diff --git a/src/osd/ECBackend.cc b/src/osd/ECBackend.cc
index 66b7dd5..3c27288 100644
--- a/src/osd/ECBackend.cc
+++ b/src/osd/ECBackend.cc
@@ -472,6 +472,15 @@ void ECBackend::continue_recovery_op(
       set<pg_shard_t> to_read;
       int r = get_min_avail_to_read_shards(
 	op.hoid, want, true, &to_read);
+      if (r != 0) {
+	// we must have lost a recovery source
+	assert(!op.recovery_progress.first);
+	dout(10) << __func__ << ": canceling recovery op for obj " << op.hoid
+		 << dendl;
+	get_parent()->cancel_pull(op.hoid);
+	recovery_ops.erase(op.hoid);
+	return;
+      }
       assert(r == 0);
       m->read(
 	this,
diff --git a/src/osd/OSD.cc b/src/osd/OSD.cc
index 2d63790..8e71f47 100644
--- a/src/osd/OSD.cc
+++ b/src/osd/OSD.cc
@@ -4128,7 +4128,7 @@ COMMAND("pg " \
 COMMAND("pg " \
 	"name=pgid,type=CephPgid " \
 	"name=cmd,type=CephChoices,strings=mark_unfound_lost " \
-	"name=mulcmd,type=CephChoices,strings=revert", \
+	"name=mulcmd,type=CephChoices,strings=revert|delete", \
 	"mark all unfound objects in this pg as lost, either removing or reverting to a prior version if one is available",
 	"osd", "rw", "cli")
 COMMAND("pg " \
@@ -4143,7 +4143,7 @@ COMMAND("pg " \
 COMMAND("query",
 	"show details of a specific pg", "osd", "r", "cli,rest")
 COMMAND("mark_unfound_lost " \
-	"name=mulcmd,type=CephChoices,strings=revert", \
+	"name=mulcmd,type=CephChoices,strings=revert|delete", \
 	"mark all unfound objects in this pg as lost, either removing or reverting to a prior version if one is available",
 	"osd", "rw", "cli,rest")
 COMMAND("list_missing " \
diff --git a/src/osd/PG.cc b/src/osd/PG.cc
index 924554c..2c86f3b 100644
--- a/src/osd/PG.cc
+++ b/src/osd/PG.cc
@@ -3880,6 +3880,7 @@ void PG::chunky_scrub(ThreadPool::TPHandle &handle)
         scrubber.received_maps.clear();
 
         {
+	  hobject_t end;
 
           // get the start and end of our scrub chunk
           //
@@ -3898,11 +3899,11 @@ void PG::chunky_scrub(ThreadPool::TPHandle &handle)
 	      cct->_conf->osd_scrub_chunk_max,
 	      0,
 	      &objects,
-	      &scrubber.end);
+	      &end);
             assert(ret >= 0);
 
             // in case we don't find a boundary: start again at the end
-            start = scrubber.end;
+            start = end;
 
             // special case: reached end of file store, implicitly a boundary
             if (objects.empty()) {
@@ -3910,19 +3911,25 @@ void PG::chunky_scrub(ThreadPool::TPHandle &handle)
             }
 
             // search backward from the end looking for a boundary
-            objects.push_back(scrubber.end);
+            objects.push_back(end);
             while (!boundary_found && objects.size() > 1) {
               hobject_t end = objects.back().get_boundary();
               objects.pop_back();
 
               if (objects.back().get_filestore_key() != end.get_filestore_key()) {
-                scrubber.end = end;
+                end = end;
                 boundary_found = true;
               }
             }
           }
-        }
 
+	  if (!_range_available_for_scrub(scrubber.start, end)) {
+	    // we'll be requeued by whatever made us unavailable for scrub
+	    done = true;
+	    break;
+	  }
+	  scrubber.end = end;
+        }
         scrubber.block_writes = true;
 
         // walk the log to find the latest update that affects our chunk
@@ -7385,6 +7392,7 @@ PG::PriorSet::PriorSet(bool ec_pool,
 	down.insert(o);
       } else if (pinfo->lost_at > interval.first) {
 	dout(10) << "build_prior  prior osd." << o << " is down, but lost_at " << pinfo->lost_at << dendl;
+	up_now.insert(so);
 	down.insert(o);
       } else {
 	dout(10) << "build_prior  prior osd." << o << " is down" << dendl;
diff --git a/src/osd/PG.h b/src/osd/PG.h
index fa5bccd..8967a56 100644
--- a/src/osd/PG.h
+++ b/src/osd/PG.h
@@ -309,10 +309,10 @@ public:
     map<hobject_t, set<pg_shard_t> > missing_loc;
     set<pg_shard_t> missing_loc_sources;
     PG *pg;
-    boost::scoped_ptr<PGBackend::IsReadablePredicate> is_readable;
-    boost::scoped_ptr<PGBackend::IsRecoverablePredicate> is_recoverable;
     set<pg_shard_t> empty_set;
   public:
+    boost::scoped_ptr<PGBackend::IsReadablePredicate> is_readable;
+    boost::scoped_ptr<PGBackend::IsRecoverablePredicate> is_recoverable;
     MissingLoc(PG *pg)
       : pg(pg) {}
     void set_backend_predicates(
@@ -353,6 +353,10 @@ public:
       return ret;
     }
 
+    const map<hobject_t, pg_missing_t::item> &get_all_missing() {
+      return needs_recovery_map;
+    }
+
     void clear() {
       needs_recovery_map.clear();
       missing_loc.clear();
@@ -1114,6 +1118,13 @@ public:
   void build_scrub_map(ScrubMap &map, ThreadPool::TPHandle &handle);
   void build_inc_scrub_map(
     ScrubMap &map, eversion_t v, ThreadPool::TPHandle &handle);
+  /**
+   * returns true if [begin, end) is good to scrub at this time
+   * a false return value obliges the implementer to requeue scrub when the
+   * condition preventing scrub clears
+   */
+  virtual bool _range_available_for_scrub(
+    const hobject_t &begin, const hobject_t &end) = 0;
   virtual void _scrub(ScrubMap &map) { }
   virtual void _scrub_clear_state() { }
   virtual void _scrub_finish() { }
diff --git a/src/osd/PGLog.h b/src/osd/PGLog.h
index 9309841..f793cbd 100644
--- a/src/osd/PGLog.h
+++ b/src/osd/PGLog.h
@@ -283,6 +283,10 @@ public:
     missing.rm(p);
   }
 
+  void missing_add_event(const pg_log_entry_t &e) {
+    missing.add_next_event(e);
+  }
+
   //////////////////// get or set log ////////////////////
 
   const IndexedLog &get_log() const { return log; }
diff --git a/src/osd/ReplicatedPG.cc b/src/osd/ReplicatedPG.cc
index 9a4f12f..95b61a3 100644
--- a/src/osd/ReplicatedPG.cc
+++ b/src/osd/ReplicatedPG.cc
@@ -652,11 +652,21 @@ int ReplicatedPG::do_command(cmdmap_t cmdmap, ostream& ss,
   else if (command == "mark_unfound_lost") {
     string mulcmd;
     cmd_getval(cct, cmdmap, "mulcmd", mulcmd);
-    if (mulcmd != "revert") {
-      ss << "mode must be 'revert'; mark and delete not yet implemented";
+    int mode = -1;
+    if (mulcmd == "revert") {
+      if (pool.info.ec_pool()) {
+	ss << "mode must be 'delete' for ec pool";
+	return -EINVAL;
+      }
+      mode = pg_log_entry_t::LOST_REVERT;
+    } else if (mulcmd == "delete") {
+      mode = pg_log_entry_t::LOST_DELETE;
+    } else {
+      ss << "mode must be 'revert' or 'delete'; mark not yet implemented";
       return -EINVAL;
     }
-    int mode = pg_log_entry_t::LOST_REVERT;
+    assert(mode == pg_log_entry_t::LOST_REVERT ||
+	   mode == pg_log_entry_t::LOST_DELETE);
 
     if (!is_primary()) {
       ss << "not primary";
@@ -675,7 +685,8 @@ int ReplicatedPG::do_command(cmdmap_t cmdmap, ostream& ss,
       return -EINVAL;
     }
 
-    ss << "pg has " << unfound << " objects unfound and apparently lost, marking";
+    ss << "pg has " << unfound
+       << " objects unfound and apparently lost, marking";
     mark_all_unfound_lost(mode);
     return 0;
   }
@@ -1189,6 +1200,12 @@ void ReplicatedPG::do_op(OpRequestRef op)
     return do_pg_op(op);
   }
 
+  if (get_osdmap()->is_blacklisted(m->get_source_addr())) {
+    dout(10) << "do_op " << m->get_source_addr() << " is blacklisted" << dendl;
+    osd->reply_op_error(op, -EBLACKLISTED);
+    return;
+  }
+
   // order this op as a write?
   bool write_ordered =
     op->may_write() ||
@@ -1306,7 +1323,7 @@ void ReplicatedPG::do_op(OpRequestRef op)
 	(!(m->get_flags() & CEPH_OSD_FLAG_BALANCE_READS) &&
 	 !(m->get_flags() & CEPH_OSD_FLAG_LOCALIZE_READS))) {
       // missing the specific snap we need; requeue and wait.
-      assert(!can_create); // only happens on a read
+      assert(!op->may_write()); // only happens on a read/cache
       wait_for_unreadable_object(missing_oid, op);
       return;
     }
@@ -1517,8 +1534,11 @@ void ReplicatedPG::do_op(OpRequestRef op)
     reply_ctx(ctx, -ENFILE);
     return;
   }
-  if (!op->may_write() && !op->may_cache() && (!obc->obs.exists ||
-					       obc->obs.oi.is_whiteout())) {
+  if (!op->may_write() &&
+      !op->may_cache() &&
+      (!obc->obs.exists ||
+       ((m->get_snapid() != CEPH_SNAPDIR) &&
+	obc->obs.oi.is_whiteout()))) {
     reply_ctx(ctx, -ENOENT);
     return;
   }
@@ -1702,7 +1722,8 @@ void ReplicatedPG::execute_ctx(OpContext *ctx)
     op->mark_started();
 
     // snap
-    if (pool.info.is_pool_snaps_mode()) {
+    if (!(m->get_flags() & CEPH_OSD_FLAG_ENFORCE_SNAPC) &&
+	pool.info.is_pool_snaps_mode()) {
       // use pool's snapc
       ctx->snapc = pool.snapc;
     } else {
@@ -3251,7 +3272,9 @@ int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
 	  break;
 	}
 	if (oi.is_dirty()) {
-	  result = start_flush(ctx, false, NULL);
+	  result = start_flush(ctx->op, ctx->obc, false, NULL, NULL);
+	  if (result == -EINPROGRESS)
+	    result = -EAGAIN;
 	} else {
 	  result = 0;
 	}
@@ -3276,7 +3299,9 @@ int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
 	}
 	hobject_t missing;
 	if (oi.is_dirty()) {
-	  result = start_flush(ctx, true, &missing);
+	  result = start_flush(ctx->op, ctx->obc, true, &missing, NULL);
+	  if (result == -EINPROGRESS)
+	    result = -EAGAIN;
 	} else {
 	  result = 0;
 	}
@@ -3523,7 +3548,8 @@ int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
 
           resp.clones.push_back(ci);
         }
-        if (ssc->snapset.head_exists) {
+        if (ssc->snapset.head_exists &&
+	    !ctx->obc->obs.oi.is_whiteout()) {
           assert(obs.exists);
           clone_info ci;
           ci.cloneid = CEPH_NOSNAP;
@@ -6053,9 +6079,12 @@ struct C_Flush : public Context {
   }
 };
 
-int ReplicatedPG::start_flush(OpContext *ctx, bool blocking, hobject_t *pmissing)
+int ReplicatedPG::start_flush(
+  OpRequestRef op, ObjectContextRef obc,
+  bool blocking, hobject_t *pmissing,
+  Context *on_flush)
 {
-  const object_info_t& oi = ctx->obc->obs.oi;
+  const object_info_t& oi = obc->obs.oi;
   const hobject_t& soid = oi.soid;
   dout(10) << __func__ << " " << soid
 	   << " v" << oi.version
@@ -6064,7 +6093,7 @@ int ReplicatedPG::start_flush(OpContext *ctx, bool blocking, hobject_t *pmissing
 	   << dendl;
 
   // verify there are no (older) check for dirty clones
-  SnapSet& snapset = ctx->obc->ssc->snapset;
+  SnapSet& snapset = obc->ssc->snapset;
   {
     dout(20) << " snapset " << snapset << dendl;
     vector<snapid_t>::reverse_iterator p = snapset.clones.rbegin();
@@ -6099,33 +6128,30 @@ int ReplicatedPG::start_flush(OpContext *ctx, bool blocking, hobject_t *pmissing
   }
 
   if (blocking)
-    ctx->obc->start_block();
+    obc->start_block();
 
   map<hobject_t,FlushOpRef>::iterator p = flush_ops.find(soid);
   if (p != flush_ops.end()) {
     FlushOpRef fop = p->second;
-    if (fop->ctx->op == ctx->op) {
+    if (fop->op == op) {
       // we couldn't take the write lock on a cache-try-flush before;
       // now we are trying again for the lock.
-      // clean up the previous ctx and use the new one.
-      close_op_ctx(fop->ctx, -EAGAIN);
-      fop->ctx = ctx;
       return try_flush_mark_clean(fop);
     }
-    if (fop->flushed_version == ctx->obc->obs.oi.user_version &&
+    if (fop->flushed_version == obc->obs.oi.user_version &&
 	(fop->blocking || !blocking)) {
       // nonblocking can join anything
       // blocking can only join a blocking flush
       dout(20) << __func__ << " piggybacking on existing flush " << dendl;
-      fop->dup_ops.push_back(ctx->op);
+      fop->dup_ops.push_back(op);
       return -EAGAIN;   // clean up this ctx; op will retry later
     }
 
     // cancel current flush since it will fail anyway, or because we
     // are blocking and the existing flush is nonblocking.
     dout(20) << __func__ << " canceling previous flush; it will fail" << dendl;
-    if (fop->ctx->op)
-      osd->reply_op_error(fop->ctx->op, -EBUSY);
+    if (fop->op)
+      osd->reply_op_error(fop->op, -EBUSY);
     while (!fop->dup_ops.empty()) {
       osd->reply_op_error(fop->dup_ops.front(), -EBUSY);
       fop->dup_ops.pop_front();
@@ -6187,16 +6213,20 @@ int ReplicatedPG::start_flush(OpContext *ctx, bool blocking, hobject_t *pmissing
       o,
       dsnapc,
       oi.mtime,
-      CEPH_OSD_FLAG_IGNORE_OVERLAY | CEPH_OSD_FLAG_ORDERSNAP,
+      (CEPH_OSD_FLAG_IGNORE_OVERLAY |
+       CEPH_OSD_FLAG_ORDERSNAP |
+       CEPH_OSD_FLAG_ENFORCE_SNAPC),
       NULL,
       NULL /* no callback, we'll rely on the ordering w.r.t the next op */);
     osd->objecter_lock.Unlock();
   }
 
   FlushOpRef fop(new FlushOp);
-  fop->ctx = ctx;
+  fop->obc = obc;
   fop->flushed_version = oi.user_version;
   fop->blocking = blocking;
+  fop->on_flush = on_flush;
+  fop->op = op;
 
   ObjectOperation o;
   if (oi.is_whiteout()) {
@@ -6213,11 +6243,12 @@ int ReplicatedPG::start_flush(OpContext *ctx, bool blocking, hobject_t *pmissing
   C_Flush *fin = new C_Flush(this, soid, get_last_peering_reset());
 
   osd->objecter_lock.Lock();
-  ceph_tid_t tid = osd->objecter->mutate(soid.oid, base_oloc, o, snapc, oi.mtime,
-				    CEPH_OSD_FLAG_IGNORE_OVERLAY,
-				    NULL,
-				    new C_OnFinisher(fin,
-						     &osd->objecter_finisher));
+  ceph_tid_t tid = osd->objecter->mutate(
+    soid.oid, base_oloc, o, snapc, oi.mtime,
+    CEPH_OSD_FLAG_IGNORE_OVERLAY | CEPH_OSD_FLAG_ENFORCE_SNAPC,
+    NULL,
+    new C_OnFinisher(fin,
+		     &osd->objecter_finisher));
   fin->tid = tid;
   fop->objecter_tid = tid;
   osd->objecter_lock.Unlock();
@@ -6241,35 +6272,41 @@ void ReplicatedPG::finish_flush(hobject_t oid, ceph_tid_t tid, int r)
 	     << " tid " << fop->objecter_tid << dendl;
     return;
   }
-  ObjectContextRef obc = fop->ctx->obc;
+  ObjectContextRef obc = fop->obc;
   fop->objecter_tid = 0;
 
   if (r < 0 && !(r == -ENOENT && fop->removal)) {
-    reply_ctx(fop->ctx, -EBUSY, obc->obs.oi.version,
-	      obc->obs.oi.user_version);
+    if (fop->op)
+      osd->reply_op_error(fop->op, -EBUSY);
     if (!fop->dup_ops.empty()) {
       dout(20) << __func__ << " requeueing dups" << dendl;
       requeue_ops(fop->dup_ops);
     }
+    if (fop->on_flush) {
+      Context *on_flush = fop->on_flush;
+      fop->on_flush = NULL;
+      on_flush->complete(-EBUSY);
+    }
     flush_ops.erase(oid);
     return;
   }
 
-  delete fop->ctx->op_t;
-  fop->ctx->op_t = pgbackend->get_transaction();
-
   r = try_flush_mark_clean(fop);
-  if (r == -EBUSY) {
-    reply_ctx(fop->ctx, -EBUSY, obc->obs.oi.version,
-	      obc->obs.oi.user_version);
+  if (r == -EBUSY && fop->op) {
+    osd->reply_op_error(fop->op, r);
   }
 }
 
 int ReplicatedPG::try_flush_mark_clean(FlushOpRef fop)
 {
-  ObjectContextRef obc = fop->ctx->obc;
+  ObjectContextRef obc = fop->obc;
   const hobject_t& oid = obc->obs.oi.soid;
 
+  if (fop->blocking) {
+    obc->stop_block();
+    kick_object_context_blocked(obc);
+  }
+
   if (fop->flushed_version != obc->obs.oi.user_version ||
       !obc->obs.exists) {
     if (obc->obs.exists)
@@ -6283,9 +6320,10 @@ int ReplicatedPG::try_flush_mark_clean(FlushOpRef fop)
       dout(20) << __func__ << " requeueing dups" << dendl;
       requeue_ops(fop->dup_ops);
     }
-    if (fop->blocking) {
-      obc->stop_block();
-      kick_object_context_blocked(obc);
+    if (fop->on_flush) {
+      Context *on_flush = fop->on_flush;
+      fop->on_flush = NULL;
+      on_flush->complete(-EBUSY);
     }
     flush_ops.erase(oid);
     if (fop->blocking)
@@ -6296,38 +6334,30 @@ int ReplicatedPG::try_flush_mark_clean(FlushOpRef fop)
   }
 
   // successfully flushed; can we clear the dirty bit?
-  if (!fop->blocking) {
-    // non-blocking: try to take the lock manually, since we don't
-    // have a ctx yet.
-    if (obc->get_write(fop->ctx->op)) {
-      dout(20) << __func__ << " took write lock" << dendl;
-    } else if (fop->ctx->op) {
-      dout(10) << __func__ << " waiting on write lock" << dendl;
-      return -EINPROGRESS;    // will retry.   this ctx is still alive!
-    } else {
-      dout(10) << __func__ << " failed write lock, no op; failing" << dendl;
-      osd->logger->inc(l_osd_tier_try_flush_fail);
-      cancel_flush(fop, false);
-      return -ECANCELED;
-    }
+  // try to take the lock manually, since we don't
+  // have a ctx yet.
+  if (obc->get_write(fop->op)) {
+    dout(20) << __func__ << " took write lock" << dendl;
+  } else if (fop->op) {
+    dout(10) << __func__ << " waiting on write lock" << dendl;
+    requeue_op(fop->op);
+    requeue_ops(fop->dup_ops);
+    return -EAGAIN;    // will retry
   } else {
-    dout(20) << __func__ << " already holding write lock: "
-	     << obc->rwstate << dendl;
-    assert(obc->rwstate.state == ObjectContext::RWState::RWWRITE);
-    assert(fop->ctx->lock_to_release == OpContext::W_LOCK);
-
-    // let other writes continue
-    obc->stop_block();
-    kick_object_context_blocked(obc);
+    dout(10) << __func__ << " failed write lock, no op; failing" << dendl;
+    osd->logger->inc(l_osd_tier_try_flush_fail);
+    cancel_flush(fop, false);
+    return -ECANCELED;
   }
 
   dout(10) << __func__ << " clearing DIRTY flag for " << oid << dendl;
-  ceph_tid_t rep_tid = osd->get_tid();
-  RepGather *repop = new_repop(fop->ctx, obc, rep_tid);
-  OpContext *ctx = fop->ctx;
-  if (!fop->blocking) {
-    ctx->lock_to_release = OpContext::W_LOCK;  // we took it above
-  }
+  RepGather *repop = simple_repop_create(fop->obc);
+  OpContext *ctx = repop->ctx;
+
+  ctx->on_finish = fop->on_flush;
+  fop->on_flush = NULL;
+
+  ctx->lock_to_release = OpContext::W_LOCK;  // we took it above
   ctx->at_version = get_next_version();
 
   ctx->new_obs = obc->obs;
@@ -6338,10 +6368,13 @@ int ReplicatedPG::try_flush_mark_clean(FlushOpRef fop)
 
   osd->logger->inc(l_osd_tier_clean);
 
-  if (!fop->dup_ops.empty()) {
-    dout(20) << __func__ << " queueing dups for " << ctx->at_version << dendl;
-    list<OpRequestRef>& ls = waiting_for_ondisk[ctx->at_version];
+  if (!fop->dup_ops.empty() || fop->op) {
+    dout(20) << __func__ << " requeueing for " << ctx->at_version << dendl;
+    list<OpRequestRef> ls;
+    if (fop->op)
+      ls.push_back(fop->op);
     ls.splice(ls.end(), fop->dup_ops);
+    requeue_ops(ls);
   }
 
   simple_repop_submit(repop);
@@ -6358,23 +6391,27 @@ int ReplicatedPG::try_flush_mark_clean(FlushOpRef fop)
 
 void ReplicatedPG::cancel_flush(FlushOpRef fop, bool requeue)
 {
-  dout(10) << __func__ << " " << fop->ctx->obc->obs.oi.soid << " tid "
+  dout(10) << __func__ << " " << fop->obc->obs.oi.soid << " tid "
 	   << fop->objecter_tid << dendl;
   if (fop->objecter_tid) {
     Mutex::Locker l(osd->objecter_lock);
     osd->objecter->op_cancel(fop->objecter_tid, -ECANCELED);
   }
   if (requeue) {
-    if (fop->ctx->op)
-      requeue_op(fop->ctx->op);
+    if (fop->op)
+      requeue_op(fop->op);
     requeue_ops(fop->dup_ops);
   }
   if (fop->blocking) {
-    fop->ctx->obc->stop_block();
-    kick_object_context_blocked(fop->ctx->obc);
+    fop->obc->stop_block();
+    kick_object_context_blocked(fop->obc);
   }
-  flush_ops.erase(fop->ctx->obc->obs.oi.soid);
-  close_op_ctx(fop->ctx, -ECANCELED);
+  if (fop->on_flush) {
+    Context *on_flush = fop->on_flush;
+    fop->on_flush = NULL;
+    on_flush->complete(-ECANCELED);
+  }
+  flush_ops.erase(fop->obc->obs.oi.soid);
 }
 
 void ReplicatedPG::cancel_flush_ops(bool requeue)
@@ -7394,6 +7431,9 @@ void ReplicatedPG::kick_object_context_blocked(ObjectContextRef obc)
   dout(10) << __func__ << " " << soid << " requeuing " << ls.size() << " requests" << dendl;
   requeue_ops(ls);
   waiting_for_blocked_object.erase(p);
+
+  if (obc->requeue_scrub_on_unblock)
+    osd->queue_for_scrub(this);
 }
 
 SnapSetContext *ReplicatedPG::create_snapset_context(const hobject_t& oid)
@@ -9038,8 +9078,10 @@ void ReplicatedPG::mark_all_unfound_lost(int what)
   utime_t mtime = ceph_clock_now(cct);
   info.last_update.epoch = get_osdmap()->get_epoch();
   const pg_missing_t &missing = pg_log.get_missing();
-  map<hobject_t, pg_missing_t::item>::const_iterator m = missing.missing.begin();
-  map<hobject_t, pg_missing_t::item>::const_iterator mend = missing.missing.end();
+  map<hobject_t, pg_missing_t::item>::const_iterator m =
+    missing_loc.get_all_missing().begin();
+  map<hobject_t, pg_missing_t::item>::const_iterator mend =
+    missing_loc.get_all_missing().end();
   while (m != mend) {
     const hobject_t &oid(m->first);
     if (!missing_loc.is_unfound(oid)) {
@@ -9088,11 +9130,11 @@ void ReplicatedPG::mark_all_unfound_lost(int what)
 	pg_log.add(e);
 	dout(10) << e << dendl;
 
-	// delete local copy?  NOT YET!  FIXME
-	if (m->second.have != eversion_t()) {
-	  assert(0 == "not implemented.. tho i'm not sure how useful it really would be.");
-	}
-	pg_log.missing_rm(m++);
+	t->remove(
+	  coll,
+	  ghobject_t(oid, ghobject_t::NO_GEN, pg_whoami.shard));
+	pg_log.missing_add_event(e);
+	++m;
 	missing_loc.recovered(oid);
       }
       break;
@@ -11159,24 +11201,15 @@ bool ReplicatedPG::agent_maybe_flush(ObjectContextRef& obc)
   // FIXME: flush anything dirty, regardless of what distribution of
   // ages we expect.
 
-  vector<OSDOp> ops;
-  ceph_tid_t rep_tid = osd->get_tid();
-  osd_reqid_t reqid(osd->get_cluster_msgr_name(), 0, rep_tid);
-  OpContext *ctx = new OpContext(OpRequestRef(), reqid, ops,
-				 &obc->obs, obc->ssc, this);
-  ctx->op_t = pgbackend->get_transaction();
-  ctx->obc = obc;
-  ctx->mtime = ceph_clock_now(cct);
-  ctx->at_version = get_next_version();
-  ctx->on_finish = new C_AgentFlushStartStop(this, obc->obs.oi.soid);
-
-  int result = start_flush(ctx, false, NULL);
+  Context *on_flush = new C_AgentFlushStartStop(this, obc->obs.oi.soid);
+  int result = start_flush(
+    OpRequestRef(), obc, false, NULL,
+    on_flush);
   if (result != -EINPROGRESS) {
+    on_flush->complete(result);
     dout(10) << __func__ << " start_flush() failed " << obc->obs.oi
       << " with " << result << dendl;
     osd->logger->inc(l_osd_agent_skip);
-    if (result != -ECANCELED)
-      close_op_ctx(ctx, result);
     return false;
   }
 
@@ -11478,6 +11511,23 @@ void ReplicatedPG::agent_estimate_atime_temp(const hobject_t& oid,
 // SCRUB
 
 
+bool ReplicatedPG::_range_available_for_scrub(
+  const hobject_t &begin, const hobject_t &end)
+{
+  pair<hobject_t, ObjectContextRef> next;
+  next.second = object_contexts.lookup(begin);
+  next.first = begin;
+  bool more = true;
+  while (more && next.first < end) {
+    if (next.second && next.second->is_blocked()) {
+      next.second->requeue_scrub_on_unblock = true;
+      return true;
+    }
+    more = object_contexts.get_next(next.first, &next);
+  }
+  return false;
+}
+
 void ReplicatedPG::_scrub(ScrubMap& scrubmap)
 {
   dout(10) << "_scrub" << dendl;
diff --git a/src/osd/ReplicatedPG.h b/src/osd/ReplicatedPG.h
index 38bdfbe..abee8bf 100644
--- a/src/osd/ReplicatedPG.h
+++ b/src/osd/ReplicatedPG.h
@@ -198,17 +198,21 @@ public:
   friend class PromoteCallback;
 
   struct FlushOp {
-    OpContext *ctx;             ///< the parent OpContext
-    list<OpRequestRef> dup_ops; ///< dup flush requests
+    ObjectContextRef obc;       ///< obc we are flushing
+    OpRequestRef op;            ///< initiating op
+    list<OpRequestRef> dup_ops; ///< bandwagon jumpers
     version_t flushed_version;  ///< user version we are flushing
     ceph_tid_t objecter_tid;    ///< copy-from request tid
     int rval;                   ///< copy-from result
     bool blocking;              ///< whether we are blocking updates
     bool removal;               ///< we are removing the backend object
+    Context *on_flush;          ///< callback, may be null
 
     FlushOp()
-      : ctx(NULL), objecter_tid(0), rval(0),
-	blocking(false), removal(false) {}
+      : objecter_tid(0), rval(0),
+	blocking(false), removal(false),
+	on_flush(NULL) {}
+    ~FlushOp() { assert(!on_flush); }
   };
   typedef boost::shared_ptr<FlushOp> FlushOpRef;
 
@@ -1221,7 +1225,11 @@ protected:
   // -- flush --
   map<hobject_t, FlushOpRef> flush_ops;
 
-  int start_flush(OpContext *ctx, bool blocking, hobject_t *pmissing);
+  /// start_flush takes ownership of on_flush iff ret == -EINPROGRESS
+  int start_flush(
+    OpRequestRef op, ObjectContextRef obc,
+    bool blocking, hobject_t *pmissing,
+    Context *on_flush);
   void finish_flush(hobject_t oid, ceph_tid_t tid, int r);
   int try_flush_mark_clean(FlushOpRef fop);
   void cancel_flush(FlushOpRef fop, bool requeue);
@@ -1233,6 +1241,8 @@ protected:
   friend struct C_Flush;
 
   // -- scrub --
+  virtual bool _range_available_for_scrub(
+    const hobject_t &begin, const hobject_t &end);
   virtual void _scrub(ScrubMap& map);
   virtual void _scrub_clear_state();
   virtual void _scrub_finish();
diff --git a/src/osd/osd_types.cc b/src/osd/osd_types.cc
index f2cf9cd..15dd661 100644
--- a/src/osd/osd_types.cc
+++ b/src/osd/osd_types.cc
@@ -47,6 +47,7 @@ const char *ceph_osd_flag_name(unsigned flag)
   case CEPH_OSD_FLAG_IGNORE_OVERLAY: return "ignore_overlay";
   case CEPH_OSD_FLAG_FLUSH: return "flush";
   case CEPH_OSD_FLAG_MAP_SNAP_CLONE: return "map_snap_clone";
+  case CEPH_OSD_FLAG_ENFORCE_SNAPC: return "enforce_snapc";
   default: return "???";
   }
 }
diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h
index 092d6cc..3289620 100644
--- a/src/osd/osd_types.h
+++ b/src/osd/osd_types.h
@@ -2690,6 +2690,7 @@ public:
   // set if writes for this object are blocked on another objects recovery
   ObjectContextRef blocked_by;      // object blocking our writes
   set<ObjectContextRef> blocking;   // objects whose writes we block
+  bool requeue_scrub_on_unblock;    // true if we need to requeue scrub on unblock
 
   // any entity in obs.oi.watchers MUST be in either watchers or unconnected_watchers.
   map<pair<uint64_t, entity_name_t>, WatchRef> watchers;
@@ -2862,7 +2863,7 @@ public:
       destructor_callback(0),
       lock("ReplicatedPG::ObjectContext::lock"),
       unstable_writes(0), readers(0), writers_waiting(0), readers_waiting(0),
-      blocked(false) {}
+      blocked(false), requeue_scrub_on_unblock(false) {}
 
   ~ObjectContext() {
     assert(rwstate.empty());
diff --git a/src/rgw/rgw_common.cc b/src/rgw/rgw_common.cc
index e413a45..58913cc 100644
--- a/src/rgw/rgw_common.cc
+++ b/src/rgw/rgw_common.cc
@@ -731,7 +731,7 @@ bool url_decode(string& src_str, string& dest_str)
 static void escape_char(char c, string& dst)
 {
   char buf[16];
-  snprintf(buf, sizeof(buf), "%%%.2X", (unsigned int)c);
+  snprintf(buf, sizeof(buf), "%%%.2X", (int)(unsigned char)c);
   dst.append(buf);
 }
 
diff --git a/src/test/librados/tier.cc b/src/test/librados/tier.cc
index 28e8e7a..ad956be 100644
--- a/src/test/librados/tier.cc
+++ b/src/test/librados/tier.cc
@@ -2123,7 +2123,7 @@ TEST_F(LibRadosTierPP, HitSetTrim) {
 
   // do a bunch of writes and make sure the hitsets rotate
   utime_t start = ceph_clock_now(NULL);
-  utime_t hard_stop = start + utime_t(count * period * 12, 0);
+  utime_t hard_stop = start + utime_t(count * period * 50, 0);
 
   time_t first = 0;
   while (true) {
@@ -4088,7 +4088,7 @@ TEST_F(LibRadosTierECPP, HitSetTrim) {
 
   // do a bunch of writes and make sure the hitsets rotate
   utime_t start = ceph_clock_now(NULL);
-  utime_t hard_stop = start + utime_t(count * period * 12, 0);
+  utime_t hard_stop = start + utime_t(count * period * 50, 0);
 
   time_t first = 0;
   int bsize = alignment;

-- 
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