]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
osd/: factor OSD::init_op_flags into seperate class
authorSamuel Just <sjust@redhat.com>
Tue, 15 Oct 2019 22:35:52 +0000 (15:35 -0700)
committerSamuel Just <sjust@redhat.com>
Tue, 3 Dec 2019 05:35:36 +0000 (21:35 -0800)
We'll want to reuse this in crimson, extract the logic
for setting flags from MOSDOp into osd_types.h.

Signed-off-by: Samuel Just <sjust@redhat.com>
src/CMakeLists.txt
src/osd/CMakeLists.txt
src/osd/OSD.cc
src/osd/OSD.h
src/osd/OSDCap.cc
src/osd/OSDCap.h
src/osd/OpRequest.cc
src/osd/OpRequest.h
src/osd/PrimaryLogPG.cc
src/osd/osd_op_util.cc [new file with mode: 0644]
src/osd/osd_op_util.h [new file with mode: 0644]

index 53546d5a75f36d9cda8644584910c9d5904f21f6..83cb101da774a77018c737cd218967d78e9f2f45 100644 (file)
@@ -349,6 +349,8 @@ set(libcommon_files
   osd/osd_types.cc
   osd/PGPeeringEvent.cc
   osd/OpRequest.cc
+  osd/ClassHandler.cc
+  osd/osd_op_util.cc
   osdc/Striper.cc
   osdc/Objecter.cc
   librbd/Features.cc
index 22e76538f7b4ea11c7f33415e215705afd4500b0..f5368319e0c6309b4b76a52a340b3ced0fea4a63 100644 (file)
@@ -22,7 +22,6 @@ set(osd_srcs
   PGBackend.cc
   OSDCap.cc
   Watch.cc
-  ClassHandler.cc
   Session.cc
   SnapMapper.cc
   ScrubStore.cc
index a02ee6f36d13429680b199db97c67b419ee17a9d..5b4c8b3c26b6dc5898d5ccf4b12ec3e90eb017f3 100644 (file)
@@ -9906,195 +9906,6 @@ void OSD::get_latest_osdmap()
 
 // --------------------------------
 
-int OSD::init_op_flags(OpRequestRef& op)
-{
-  auto m = op->get_req<MOSDOp>();
-  vector<OSDOp>::const_iterator iter;
-
-  // client flags have no bearing on whether an op is a read, write, etc.
-  op->rmw_flags = 0;
-
-  if (m->has_flag(CEPH_OSD_FLAG_RWORDERED)) {
-    op->set_force_rwordered();
-  }
-  if (m->has_flag(CEPH_OSD_FLAG_RETURNVEC)) {
-    op->set_returnvec();
-  }
-
-  // set bits based on op codes, called methods.
-  for (iter = m->ops.begin(); iter != m->ops.end(); ++iter) {
-    if ((iter->op.op == CEPH_OSD_OP_WATCH &&
-        iter->op.watch.op == CEPH_OSD_WATCH_OP_PING)) {
-      /* This a bit odd.  PING isn't actually a write.  It can't
-       * result in an update to the object_info.  PINGs also aren't
-       * resent, so there's no reason to write out a log entry.
-       *
-       * However, we pipeline them behind writes, so let's force
-       * the write_ordered flag.
-       */
-      op->set_force_rwordered();
-    } else {
-      if (ceph_osd_op_mode_modify(iter->op.op))
-       op->set_write();
-    }
-    if (ceph_osd_op_mode_read(iter->op.op))
-      op->set_read();
-
-    // set READ flag if there are src_oids
-    if (iter->soid.oid.name.length())
-      op->set_read();
-
-    // set PGOP flag if there are PG ops
-    if (ceph_osd_op_type_pg(iter->op.op))
-      op->set_pg_op();
-
-    if (ceph_osd_op_mode_cache(iter->op.op))
-      op->set_cache();
-
-    // check for ec base pool
-    int64_t poolid = m->get_pg().pool();
-    const pg_pool_t *pool = osdmap->get_pg_pool(poolid);
-    if (pool && pool->is_tier()) {
-      const pg_pool_t *base_pool = osdmap->get_pg_pool(pool->tier_of);
-      if (base_pool && base_pool->require_rollback()) {
-        if ((iter->op.op != CEPH_OSD_OP_READ) &&
-            (iter->op.op != CEPH_OSD_OP_CHECKSUM) &&
-            (iter->op.op != CEPH_OSD_OP_CMPEXT) &&
-            (iter->op.op != CEPH_OSD_OP_STAT) &&
-            (iter->op.op != CEPH_OSD_OP_ISDIRTY) &&
-            (iter->op.op != CEPH_OSD_OP_UNDIRTY) &&
-            (iter->op.op != CEPH_OSD_OP_GETXATTR) &&
-            (iter->op.op != CEPH_OSD_OP_GETXATTRS) &&
-            (iter->op.op != CEPH_OSD_OP_CMPXATTR) &&
-            (iter->op.op != CEPH_OSD_OP_ASSERT_VER) &&
-            (iter->op.op != CEPH_OSD_OP_LIST_WATCHERS) &&
-            (iter->op.op != CEPH_OSD_OP_LIST_SNAPS) &&
-            (iter->op.op != CEPH_OSD_OP_SETALLOCHINT) &&
-            (iter->op.op != CEPH_OSD_OP_WRITEFULL) &&
-            (iter->op.op != CEPH_OSD_OP_ROLLBACK) &&
-            (iter->op.op != CEPH_OSD_OP_CREATE) &&
-            (iter->op.op != CEPH_OSD_OP_DELETE) &&
-            (iter->op.op != CEPH_OSD_OP_SETXATTR) &&
-            (iter->op.op != CEPH_OSD_OP_RMXATTR) &&
-            (iter->op.op != CEPH_OSD_OP_STARTSYNC) &&
-            (iter->op.op != CEPH_OSD_OP_COPY_GET) &&
-            (iter->op.op != CEPH_OSD_OP_COPY_FROM)) {
-          op->set_promote();
-        }
-      }
-    }
-
-    switch (iter->op.op) {
-    case CEPH_OSD_OP_CALL:
-      {
-       bufferlist::iterator bp = const_cast<bufferlist&>(iter->indata).begin();
-       int is_write, is_read;
-       string cname, mname;
-       bp.copy(iter->op.cls.class_len, cname);
-       bp.copy(iter->op.cls.method_len, mname);
-
-       ClassHandler::ClassData *cls;
-       int r = ClassHandler::get_instance().open_class(cname, &cls);
-       if (r) {
-         derr << "class " << cname << " open got " << cpp_strerror(r) << dendl;
-         if (r == -ENOENT)
-           r = -EOPNOTSUPP;
-         else if (r != -EPERM) // propagate permission errors
-           r = -EIO;
-         return r;
-       }
-       int flags = cls->get_method_flags(mname);
-       if (flags < 0) {
-         if (flags == -ENOENT)
-           r = -EOPNOTSUPP;
-         else
-           r = flags;
-         return r;
-       }
-       is_read = flags & CLS_METHOD_RD;
-       is_write = flags & CLS_METHOD_WR;
-        bool is_promote = flags & CLS_METHOD_PROMOTE;
-
-       dout(10) << "class " << cname << " method " << mname << " "
-                << "flags=" << (is_read ? "r" : "")
-                             << (is_write ? "w" : "")
-                             << (is_promote ? "p" : "")
-                 << dendl;
-       if (is_read)
-         op->set_class_read();
-       if (is_write)
-         op->set_class_write();
-        if (is_promote)
-          op->set_promote();
-        op->add_class(std::move(cname), std::move(mname), is_read, is_write,
-                      cls->whitelisted);
-       break;
-      }
-
-    case CEPH_OSD_OP_WATCH:
-      // force the read bit for watch since it is depends on previous
-      // watch state (and may return early if the watch exists) or, in
-      // the case of ping, is simply a read op.
-      op->set_read();
-      // fall through
-    case CEPH_OSD_OP_NOTIFY:
-    case CEPH_OSD_OP_NOTIFY_ACK:
-      {
-        op->set_promote();
-        break;
-      }
-
-    case CEPH_OSD_OP_DELETE:
-      // if we get a delete with FAILOK we can skip handle cache. without
-      // FAILOK we still need to promote (or do something smarter) to
-      // determine whether to return ENOENT or 0.
-      if (iter == m->ops.begin() &&
-         iter->op.flags == CEPH_OSD_OP_FLAG_FAILOK) {
-       op->set_skip_handle_cache();
-      }
-      // skip promotion when proxying a delete op
-      if (m->ops.size() == 1) {
-       op->set_skip_promote();
-      }
-      break;
-
-    case CEPH_OSD_OP_CACHE_TRY_FLUSH:
-    case CEPH_OSD_OP_CACHE_FLUSH:
-    case CEPH_OSD_OP_CACHE_EVICT:
-      // If try_flush/flush/evict is the only op, can skip handle cache.
-      if (m->ops.size() == 1) {
-       op->set_skip_handle_cache();
-      }
-      break;
-
-    case CEPH_OSD_OP_READ:
-    case CEPH_OSD_OP_SYNC_READ:
-    case CEPH_OSD_OP_SPARSE_READ:
-    case CEPH_OSD_OP_CHECKSUM:
-    case CEPH_OSD_OP_WRITEFULL:
-      if (m->ops.size() == 1 &&
-          (iter->op.flags & CEPH_OSD_OP_FLAG_FADVISE_NOCACHE ||
-           iter->op.flags & CEPH_OSD_OP_FLAG_FADVISE_DONTNEED)) {
-        op->set_skip_promote();
-      }
-      break;
-
-    // force promotion when pin an object in cache tier
-    case CEPH_OSD_OP_CACHE_PIN:
-      op->set_promote();
-      break;
-
-    default:
-      break;
-    }
-  }
-
-  if (op->rmw_flags == 0)
-    return -EINVAL;
-
-  return 0;
-}
-
 void OSD::set_perf_queries(
     const std::map<OSDPerfMetricQuery, OSDPerfMetricLimits> &queries) {
   dout(10) << "setting " << queries.size() << " queries" << dendl;
index 353164118a447c98991e0456de456dea406066d2..58ef72b73436ebd40ad3fdba1a85f786f02ee3c2 100644 (file)
@@ -2037,8 +2037,6 @@ private:
   void handle_fast_scrub(struct MOSDScrub2 *m);
   void handle_osd_ping(class MOSDPing *m);
 
-  int init_op_flags(OpRequestRef& op);
-
   size_t get_num_cache_shards();
   int get_num_op_shards();
   int get_num_op_threads();
index b6df192c31ea1c7a5acc65c92fa1e6cd1700a39d..dfc7eae9ec37816a6ac7434c7c459c503f31c371 100644 (file)
@@ -249,7 +249,7 @@ bool OSDCapGrant::is_capable(
   const string& object,
   bool op_may_read,
   bool op_may_write,
-  const std::vector<OpRequest::ClassInfo>& classes,
+  const std::vector<OpInfo::ClassInfo>& classes,
   const entity_addr_t& addr,
   std::vector<bool>* class_allowed) const
 {
@@ -377,7 +377,7 @@ bool OSDCap::is_capable(const string& pool_name, const string& ns,
                        const OSDCapPoolTag::app_map_t& application_metadata,
                        const string& object,
                         bool op_may_read, bool op_may_write,
-                       const std::vector<OpRequest::ClassInfo>& classes,
+                       const std::vector<OpInfo::ClassInfo>& classes,
                        const entity_addr_t& addr) const
 {
   std::vector<bool> class_allowed(classes.size(), false);
index 2bb4e21ca1a4618f9a221659f5669e5f823d34e2..d6a29b1594593acf8bad25432ea30da1deb206a0 100644 (file)
@@ -211,7 +211,7 @@ struct OSDCapGrant {
   bool is_capable(const string& pool_name, const string& ns,
                  const OSDCapPoolTag::app_map_t& application_metadata,
                   const string& object, bool op_may_read, bool op_may_write,
-                  const std::vector<OpRequest::ClassInfo>& classes,
+                  const std::vector<OpInfo::ClassInfo>& classes,
                  const entity_addr_t& addr,
                   std::vector<bool>* class_allowed) const;
 
@@ -249,7 +249,7 @@ struct OSDCap {
   bool is_capable(const string& pool_name, const string& ns,
                  const OSDCapPoolTag::app_map_t& application_metadata,
                  const string& object, bool op_may_read, bool op_may_write,
-                 const std::vector<OpRequest::ClassInfo>& classes,
+                 const std::vector<OpInfo::ClassInfo>& classes,
                  const entity_addr_t& addr) const;
 };
 
index f37e1d7839c056a91351ff8eb2200ba31a5c6149..0eb92c23a6a3e2642d1c033203cd8d6218e46821 100644 (file)
@@ -32,7 +32,6 @@ using ceph::Formatter;
 
 OpRequest::OpRequest(Message* req, OpTracker* tracker)
     : TrackedOp(tracker, req->get_throttle_stamp()),
-      rmw_flags(0),
       request(req),
       hit_flag_points(0),
       latest_flag_point(0),
@@ -101,66 +100,22 @@ void OpRequest::_unregistered() {
   request->set_connection(nullptr);
 }
 
-bool OpRequest::check_rmw(int flag) const {
-  ceph_assert(rmw_flags != 0);
-  return rmw_flags & flag;
-}
-bool OpRequest::may_read() const {
-  return need_read_cap() || check_rmw(CEPH_OSD_RMW_FLAG_CLASS_READ);
-}
-bool OpRequest::may_write() const {
-  return need_write_cap() || check_rmw(CEPH_OSD_RMW_FLAG_CLASS_WRITE);
-}
-bool OpRequest::may_cache() const { return check_rmw(CEPH_OSD_RMW_FLAG_CACHE); }
-bool OpRequest::rwordered_forced() const {
-  return check_rmw(CEPH_OSD_RMW_FLAG_RWORDERED);
-}
-bool OpRequest::rwordered() const {
-  return may_write() || may_cache() || rwordered_forced();
-}
+int OpRequest::maybe_init_op_info(const OSDMap &osdmap) {
+  if (op_info.get_flags())
+    return 0;
 
-bool OpRequest::includes_pg_op() { return check_rmw(CEPH_OSD_RMW_FLAG_PGOP); }
-bool OpRequest::need_read_cap() const {
-  return check_rmw(CEPH_OSD_RMW_FLAG_READ);
-}
-bool OpRequest::need_write_cap() const {
-  return check_rmw(CEPH_OSD_RMW_FLAG_WRITE);
-}
-bool OpRequest::need_promote() {
-  return check_rmw(CEPH_OSD_RMW_FLAG_FORCE_PROMOTE);
-}
-bool OpRequest::need_skip_handle_cache() {
-  return check_rmw(CEPH_OSD_RMW_FLAG_SKIP_HANDLE_CACHE);
-}
-bool OpRequest::need_skip_promote() {
-  return check_rmw(CEPH_OSD_RMW_FLAG_SKIP_PROMOTE);
-}
-bool OpRequest::allows_returnvec() const {
-  return check_rmw(CEPH_OSD_RMW_FLAG_RETURNVEC);
-}
+  auto m = get_req<MOSDOp>();
 
-void OpRequest::set_rmw_flags(int flags) {
 #ifdef WITH_LTTNG
-  int old_rmw_flags = rmw_flags;
+  auto old_rmw_flags = op_info.get_flags();
 #endif
-  rmw_flags |= flags;
+  auto ret = op_info.set_from_op(m, osdmap);
   tracepoint(oprequest, set_rmw_flags, reqid.name._type,
             reqid.name._num, reqid.tid, reqid.inc,
-            flags, old_rmw_flags, rmw_flags);
+            op_info.get_flags(), old_rmw_flags, op_info.get_flags());
+  return ret;
 }
 
-void OpRequest::set_read() { set_rmw_flags(CEPH_OSD_RMW_FLAG_READ); }
-void OpRequest::set_write() { set_rmw_flags(CEPH_OSD_RMW_FLAG_WRITE); }
-void OpRequest::set_class_read() { set_rmw_flags(CEPH_OSD_RMW_FLAG_CLASS_READ); }
-void OpRequest::set_class_write() { set_rmw_flags(CEPH_OSD_RMW_FLAG_CLASS_WRITE); }
-void OpRequest::set_pg_op() { set_rmw_flags(CEPH_OSD_RMW_FLAG_PGOP); }
-void OpRequest::set_cache() { set_rmw_flags(CEPH_OSD_RMW_FLAG_CACHE); }
-void OpRequest::set_promote() { set_rmw_flags(CEPH_OSD_RMW_FLAG_FORCE_PROMOTE); }
-void OpRequest::set_skip_handle_cache() { set_rmw_flags(CEPH_OSD_RMW_FLAG_SKIP_HANDLE_CACHE); }
-void OpRequest::set_skip_promote() { set_rmw_flags(CEPH_OSD_RMW_FLAG_SKIP_PROMOTE); }
-void OpRequest::set_force_rwordered() { set_rmw_flags(CEPH_OSD_RMW_FLAG_RWORDERED); }
-void OpRequest::set_returnvec() { set_rmw_flags(CEPH_OSD_RMW_FLAG_RETURNVEC); }
-
 void OpRequest::mark_flag_point(uint8_t flag, const char *s) {
 #ifdef WITH_LTTNG
   uint8_t old_flags = hit_flag_points;
@@ -169,7 +124,7 @@ void OpRequest::mark_flag_point(uint8_t flag, const char *s) {
   hit_flag_points |= flag;
   latest_flag_point = flag;
   tracepoint(oprequest, mark_flag_point, reqid.name._type,
-            reqid.name._num, reqid.tid, reqid.inc, rmw_flags,
+            reqid.name._num, reqid.tid, reqid.inc, op_info.get_flags(),
             flag, s, old_flags, hit_flag_points);
 }
 
@@ -181,7 +136,7 @@ void OpRequest::mark_flag_point_string(uint8_t flag, const string& s) {
   hit_flag_points |= flag;
   latest_flag_point = flag;
   tracepoint(oprequest, mark_flag_point, reqid.name._type,
-            reqid.name._num, reqid.tid, reqid.inc, rmw_flags,
+            reqid.name._num, reqid.tid, reqid.inc, op_info.get_flags(),
             flag, s.c_str(), old_flags, hit_flag_points);
 }
 
@@ -213,9 +168,3 @@ bool OpRequest::filter_out(const set<string>& filters)
   return false;
 }
 
-ostream& operator<<(ostream& out, const OpRequest::ClassInfo& i)
-{
-  out << "class " << i.class_name << " method " << i.method_name
-      << " rd " << i.read << " wr " << i.write << " wl " << i.whitelisted;
-  return out;
-}
index 565ecb8969b2c79c89ebfb045319161225ea7125..dc5b5e34b1f2d28cac3f653736885c4baddec828 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef OPREQUEST_H_
 #define OPREQUEST_H_
 
+#include "osd/osd_op_util.h"
 #include "osd/osd_types.h"
 #include "common/TrackedOp.h"
 
 struct OpRequest : public TrackedOp {
   friend class OpTracker;
 
-  // rmw flags
-  int rmw_flags;
-
-  bool check_rmw(int flag) const ;
-  bool may_read() const;
-  bool may_write() const;
-  bool may_cache() const;
-  bool rwordered_forced() const;
-  bool rwordered() const;
-  bool includes_pg_op();
-  bool need_read_cap() const;
-  bool need_write_cap() const;
-  bool need_promote();
-  bool need_skip_handle_cache();
-  bool need_skip_promote();
-  bool allows_returnvec() const;
-  void set_read();
-  void set_write();
-  void set_cache();
-  void set_class_read();
-  void set_class_write();
-  void set_pg_op();
-  void set_promote();
-  void set_skip_handle_cache();
-  void set_skip_promote();
-  void set_force_rwordered();
-  void set_returnvec();
-
-  struct ClassInfo {
-    ClassInfo(std::string&& class_name, std::string&& method_name,
-              bool read, bool write, bool whitelisted) :
-      class_name(std::move(class_name)), method_name(std::move(method_name)),
-      read(read), write(write), whitelisted(whitelisted)
-    {}
-    const std::string class_name;
-    const std::string method_name;
-    const bool read, write, whitelisted;
-  };
-
-  void add_class(std::string&& class_name, std::string&& method_name,
-                 bool read, bool write, bool whitelisted) {
-    classes_.emplace_back(std::move(class_name), std::move(method_name),
-                          read, write, whitelisted);
-  }
+private:
+  OpInfo op_info;
 
-  std::vector<ClassInfo> classes() const {
-    return classes_;
+public:
+  int maybe_init_op_info(const OSDMap &osdmap);
+
+  auto get_flags() const { return op_info.get_flags(); }
+  bool op_info_needs_init() const { return op_info.get_flags() == 0; }
+  bool check_rmw(int flag) const { return op_info.check_rmw(flag); }
+  bool may_read() const { return op_info.may_read(); }
+  bool may_write() const { return op_info.may_write(); }
+  bool may_cache() const { return op_info.may_cache(); }
+  bool rwordered_forced() const { return op_info.rwordered_forced(); }
+  bool rwordered() const { return op_info.rwordered(); }
+  bool includes_pg_op() const { return op_info.includes_pg_op(); }
+  bool need_read_cap() const { return op_info.need_read_cap(); }
+  bool need_write_cap() const { return op_info.need_write_cap(); }
+  bool need_promote() const { return op_info.need_promote(); }
+  bool need_skip_handle_cache() const { return op_info.need_skip_handle_cache(); }
+  bool need_skip_promote() const { return op_info.need_skip_promote(); }
+  bool allows_returnvec() const { return op_info.allows_returnvec(); }
+
+  std::vector<OpInfo::ClassInfo> classes() const {
+    return op_info.get_classes();
   }
 
   void _dump(ceph::Formatter *f) const override;
@@ -93,8 +71,6 @@ private:
   static const uint8_t flag_sub_op_sent = 1 << 4;
   static const uint8_t flag_commit_sent = 1 << 5;
 
-  std::vector<ClassInfo> classes_;
-
   OpRequest(Message *req, OpTracker *tracker);
 
 protected:
@@ -173,13 +149,10 @@ public:
   typedef boost::intrusive_ptr<OpRequest> Ref;
 
 private:
-  void set_rmw_flags(int flags);
   void mark_flag_point(uint8_t flag, const char *s);
   void mark_flag_point_string(uint8_t flag, const std::string& s);
 };
 
 typedef OpRequest::Ref OpRequestRef;
 
-std::ostream& operator<<(std::ostream& out, const OpRequest::ClassInfo& i);
-
 #endif /* OPREQUEST_H_ */
index e06fa6c8c55896bc6a3749d1e371f8a2043a8790..3cd06d5d2da3113d5c07970d7c1c91b7d6a77587 100644 (file)
@@ -1849,8 +1849,8 @@ void PrimaryLogPG::do_op(OpRequestRef& op)
     return;
   }
 
-  if (op->rmw_flags == 0) {
-    int r = osd->osd->init_op_flags(op);
+  {
+    int r = op->maybe_init_op_info(*get_osdmap());
     if (r) {
       osd->reply_op_error(op, r);
       return;
diff --git a/src/osd/osd_op_util.cc b/src/osd/osd_op_util.cc
new file mode 100644 (file)
index 0000000..f1aaf61
--- /dev/null
@@ -0,0 +1,256 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "osd/osd_op_util.h"
+
+#include "osd/ClassHandler.h"
+#include "messages/MOSDOp.h"
+
+bool OpInfo::check_rmw(int flag) const {
+  ceph_assert(rmw_flags != 0);
+  return rmw_flags & flag;
+}
+bool OpInfo::may_read() const {
+  return need_read_cap() || check_rmw(CEPH_OSD_RMW_FLAG_CLASS_READ);
+}
+bool OpInfo::may_write() const {
+  return need_write_cap() || check_rmw(CEPH_OSD_RMW_FLAG_CLASS_WRITE);
+}
+bool OpInfo::may_cache() const { return check_rmw(CEPH_OSD_RMW_FLAG_CACHE); }
+bool OpInfo::rwordered_forced() const {
+  return check_rmw(CEPH_OSD_RMW_FLAG_RWORDERED);
+}
+bool OpInfo::rwordered() const {
+  return may_write() || may_cache() || rwordered_forced();
+}
+
+bool OpInfo::includes_pg_op() const {
+  return check_rmw(CEPH_OSD_RMW_FLAG_PGOP);
+}
+bool OpInfo::need_read_cap() const {
+  return check_rmw(CEPH_OSD_RMW_FLAG_READ);
+}
+bool OpInfo::need_write_cap() const {
+  return check_rmw(CEPH_OSD_RMW_FLAG_WRITE);
+}
+bool OpInfo::need_promote() const {
+  return check_rmw(CEPH_OSD_RMW_FLAG_FORCE_PROMOTE);
+}
+bool OpInfo::need_skip_handle_cache() const {
+  return check_rmw(CEPH_OSD_RMW_FLAG_SKIP_HANDLE_CACHE);
+}
+bool OpInfo::need_skip_promote() const {
+  return check_rmw(CEPH_OSD_RMW_FLAG_SKIP_PROMOTE);
+}
+bool OpInfo::allows_returnvec() const {
+  return check_rmw(CEPH_OSD_RMW_FLAG_RETURNVEC);
+}
+
+void OpInfo::set_rmw_flags(int flags) {
+  rmw_flags |= flags;
+}
+
+void OpInfo::set_read() { set_rmw_flags(CEPH_OSD_RMW_FLAG_READ); }
+void OpInfo::set_write() { set_rmw_flags(CEPH_OSD_RMW_FLAG_WRITE); }
+void OpInfo::set_class_read() { set_rmw_flags(CEPH_OSD_RMW_FLAG_CLASS_READ); }
+void OpInfo::set_class_write() { set_rmw_flags(CEPH_OSD_RMW_FLAG_CLASS_WRITE); }
+void OpInfo::set_pg_op() { set_rmw_flags(CEPH_OSD_RMW_FLAG_PGOP); }
+void OpInfo::set_cache() { set_rmw_flags(CEPH_OSD_RMW_FLAG_CACHE); }
+void OpInfo::set_promote() { set_rmw_flags(CEPH_OSD_RMW_FLAG_FORCE_PROMOTE); }
+void OpInfo::set_skip_handle_cache() { set_rmw_flags(CEPH_OSD_RMW_FLAG_SKIP_HANDLE_CACHE); }
+void OpInfo::set_skip_promote() { set_rmw_flags(CEPH_OSD_RMW_FLAG_SKIP_PROMOTE); }
+void OpInfo::set_force_rwordered() { set_rmw_flags(CEPH_OSD_RMW_FLAG_RWORDERED); }
+void OpInfo::set_returnvec() { set_rmw_flags(CEPH_OSD_RMW_FLAG_RETURNVEC); }
+
+
+int OpInfo::set_from_op(
+  const MOSDOp *m,
+  const OSDMap &osdmap)
+{
+  vector<OSDOp>::const_iterator iter;
+
+  // client flags have no bearing on whether an op is a read, write, etc.
+  clear();
+
+  if (m->has_flag(CEPH_OSD_FLAG_RWORDERED)) {
+    set_force_rwordered();
+  }
+  if (m->has_flag(CEPH_OSD_FLAG_RETURNVEC)) {
+    set_returnvec();
+  }
+
+  // set bits based on op codes, called methods.
+  for (iter = m->ops.begin(); iter != m->ops.end(); ++iter) {
+    if ((iter->op.op == CEPH_OSD_OP_WATCH &&
+        iter->op.watch.op == CEPH_OSD_WATCH_OP_PING)) {
+      /* This a bit odd.  PING isn't actually a write.  It can't
+       * result in an update to the object_info.  PINGs also aren't
+       * resent, so there's no reason to write out a log entry.
+       *
+       * However, we pipeline them behind writes, so let's force
+       * the write_ordered flag.
+       */
+      set_force_rwordered();
+    } else {
+      if (ceph_osd_op_mode_modify(iter->op.op))
+       set_write();
+    }
+    if (ceph_osd_op_mode_read(iter->op.op))
+      set_read();
+
+    // set READ flag if there are src_oids
+    if (iter->soid.oid.name.length())
+      set_read();
+
+    // set PGOP flag if there are PG ops
+    if (ceph_osd_op_type_pg(iter->op.op))
+      set_pg_op();
+
+    if (ceph_osd_op_mode_cache(iter->op.op))
+      set_cache();
+
+    // check for ec base pool
+    int64_t poolid = m->get_pg().pool();
+    const pg_pool_t *pool = osdmap.get_pg_pool(poolid);
+    if (pool && pool->is_tier()) {
+      const pg_pool_t *base_pool = osdmap.get_pg_pool(pool->tier_of);
+      if (base_pool && base_pool->require_rollback()) {
+        if ((iter->op.op != CEPH_OSD_OP_READ) &&
+            (iter->op.op != CEPH_OSD_OP_CHECKSUM) &&
+            (iter->op.op != CEPH_OSD_OP_CMPEXT) &&
+            (iter->op.op != CEPH_OSD_OP_STAT) &&
+            (iter->op.op != CEPH_OSD_OP_ISDIRTY) &&
+            (iter->op.op != CEPH_OSD_OP_UNDIRTY) &&
+            (iter->op.op != CEPH_OSD_OP_GETXATTR) &&
+            (iter->op.op != CEPH_OSD_OP_GETXATTRS) &&
+            (iter->op.op != CEPH_OSD_OP_CMPXATTR) &&
+            (iter->op.op != CEPH_OSD_OP_ASSERT_VER) &&
+            (iter->op.op != CEPH_OSD_OP_LIST_WATCHERS) &&
+            (iter->op.op != CEPH_OSD_OP_LIST_SNAPS) &&
+            (iter->op.op != CEPH_OSD_OP_SETALLOCHINT) &&
+            (iter->op.op != CEPH_OSD_OP_WRITEFULL) &&
+            (iter->op.op != CEPH_OSD_OP_ROLLBACK) &&
+            (iter->op.op != CEPH_OSD_OP_CREATE) &&
+            (iter->op.op != CEPH_OSD_OP_DELETE) &&
+            (iter->op.op != CEPH_OSD_OP_SETXATTR) &&
+            (iter->op.op != CEPH_OSD_OP_RMXATTR) &&
+            (iter->op.op != CEPH_OSD_OP_STARTSYNC) &&
+            (iter->op.op != CEPH_OSD_OP_COPY_GET) &&
+            (iter->op.op != CEPH_OSD_OP_COPY_FROM)) {
+          set_promote();
+        }
+      }
+    }
+
+    switch (iter->op.op) {
+    case CEPH_OSD_OP_CALL:
+      {
+       bufferlist::iterator bp = const_cast<bufferlist&>(iter->indata).begin();
+       int is_write, is_read;
+       string cname, mname;
+       bp.copy(iter->op.cls.class_len, cname);
+       bp.copy(iter->op.cls.method_len, mname);
+
+       ClassHandler::ClassData *cls;
+       int r = ClassHandler::get_instance().open_class(cname, &cls);
+       if (r) {
+         if (r == -ENOENT)
+           r = -EOPNOTSUPP;
+         else if (r != -EPERM) // propagate permission errors
+           r = -EIO;
+         return r;
+       }
+       int flags = cls->get_method_flags(mname);
+       if (flags < 0) {
+         if (flags == -ENOENT)
+           r = -EOPNOTSUPP;
+         else
+           r = flags;
+         return r;
+       }
+       is_read = flags & CLS_METHOD_RD;
+       is_write = flags & CLS_METHOD_WR;
+        bool is_promote = flags & CLS_METHOD_PROMOTE;
+
+       if (is_read)
+         set_class_read();
+       if (is_write)
+         set_class_write();
+        if (is_promote)
+          set_promote();
+        add_class(std::move(cname), std::move(mname), is_read, is_write,
+                      cls->whitelisted);
+       break;
+      }
+
+    case CEPH_OSD_OP_WATCH:
+      // force the read bit for watch since it is depends on previous
+      // watch state (and may return early if the watch exists) or, in
+      // the case of ping, is simply a read op.
+      set_read();
+      // fall through
+    case CEPH_OSD_OP_NOTIFY:
+    case CEPH_OSD_OP_NOTIFY_ACK:
+      {
+        set_promote();
+        break;
+      }
+
+    case CEPH_OSD_OP_DELETE:
+      // if we get a delete with FAILOK we can skip handle cache. without
+      // FAILOK we still need to promote (or do something smarter) to
+      // determine whether to return ENOENT or 0.
+      if (iter == m->ops.begin() &&
+         iter->op.flags == CEPH_OSD_OP_FLAG_FAILOK) {
+       set_skip_handle_cache();
+      }
+      // skip promotion when proxying a delete op
+      if (m->ops.size() == 1) {
+       set_skip_promote();
+      }
+      break;
+
+    case CEPH_OSD_OP_CACHE_TRY_FLUSH:
+    case CEPH_OSD_OP_CACHE_FLUSH:
+    case CEPH_OSD_OP_CACHE_EVICT:
+      // If try_flush/flush/evict is the only op, can skip handle cache.
+      if (m->ops.size() == 1) {
+       set_skip_handle_cache();
+      }
+      break;
+
+    case CEPH_OSD_OP_READ:
+    case CEPH_OSD_OP_SYNC_READ:
+    case CEPH_OSD_OP_SPARSE_READ:
+    case CEPH_OSD_OP_CHECKSUM:
+    case CEPH_OSD_OP_WRITEFULL:
+      if (m->ops.size() == 1 &&
+          (iter->op.flags & CEPH_OSD_OP_FLAG_FADVISE_NOCACHE ||
+           iter->op.flags & CEPH_OSD_OP_FLAG_FADVISE_DONTNEED)) {
+        set_skip_promote();
+      }
+      break;
+
+    // force promotion when pin an object in cache tier
+    case CEPH_OSD_OP_CACHE_PIN:
+      set_promote();
+      break;
+
+    default:
+      break;
+    }
+  }
+
+  if (rmw_flags == 0)
+    return -EINVAL;
+
+  return 0;
+
+}
+
+ostream& operator<<(ostream& out, const OpInfo::ClassInfo& i)
+{
+  out << "class " << i.class_name << " method " << i.method_name
+      << " rd " << i.read << " wr " << i.write << " wl " << i.whitelisted;
+  return out;
+}
diff --git a/src/osd/osd_op_util.h b/src/osd/osd_op_util.h
new file mode 100644 (file)
index 0000000..92dac0f
--- /dev/null
@@ -0,0 +1,82 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#pragma once
+
+#include <vector>
+#include <string>
+
+#include "osd/OSDMap.h"
+
+class MOSDOp;
+class OpInfo {
+public:
+  struct ClassInfo {
+    ClassInfo(std::string&& class_name, std::string&& method_name,
+              bool read, bool write, bool whitelisted) :
+      class_name(std::move(class_name)), method_name(std::move(method_name)),
+      read(read), write(write), whitelisted(whitelisted)
+    {}
+    const std::string class_name;
+    const std::string method_name;
+    const bool read, write, whitelisted;
+  };
+
+private:
+  uint64_t rmw_flags = 0;
+  std::vector<ClassInfo> classes;
+
+  void set_rmw_flags(int flags);
+
+  void add_class(std::string&& class_name, std::string&& method_name,
+                 bool read, bool write, bool whitelisted) {
+    classes.emplace_back(std::move(class_name), std::move(method_name),
+                          read, write, whitelisted);
+  }
+
+public:
+
+  void clear() {
+    rmw_flags = 0;
+  }
+
+  uint64_t get_flags() const {
+    return rmw_flags;
+  }
+
+  bool check_rmw(int flag) const ;
+  bool may_read() const;
+  bool may_write() const;
+  bool may_cache() const;
+  bool rwordered_forced() const;
+  bool rwordered() const;
+  bool includes_pg_op() const;
+  bool need_read_cap() const;
+  bool need_write_cap() const;
+  bool need_promote() const;
+  bool need_skip_handle_cache() const;
+  bool need_skip_promote() const;
+  bool allows_returnvec() const;
+
+  void set_read();
+  void set_write();
+  void set_cache();
+  void set_class_read();
+  void set_class_write();
+  void set_pg_op();
+  void set_promote();
+  void set_skip_handle_cache();
+  void set_skip_promote();
+  void set_force_rwordered();
+  void set_returnvec();
+
+  int set_from_op(
+    const MOSDOp *m,
+    const OSDMap &osdmap);
+
+  std::vector<ClassInfo> get_classes() const {
+    return classes;
+  }
+};
+
+std::ostream& operator<<(std::ostream& out, const OpInfo::ClassInfo& i);