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
PGBackend.cc
OSDCap.cc
Watch.cc
- ClassHandler.cc
Session.cc
SnapMapper.cc
ScrubStore.cc
// --------------------------------
-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;
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();
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
{
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);
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;
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;
};
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),
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;
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);
}
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);
}
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;
-}
#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;
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:
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_ */
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;
--- /dev/null
+// -*- 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;
+}
--- /dev/null
+// -*- 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);