summaryrefslogtreecommitdiffstats
path: root/src/messages/MClientRequest.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/messages/MClientRequest.h')
-rw-r--r--src/messages/MClientRequest.h375
1 files changed, 375 insertions, 0 deletions
diff --git a/src/messages/MClientRequest.h b/src/messages/MClientRequest.h
new file mode 100644
index 000000000..f63657d2e
--- /dev/null
+++ b/src/messages/MClientRequest.h
@@ -0,0 +1,375 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+
+#ifndef CEPH_MCLIENTREQUEST_H
+#define CEPH_MCLIENTREQUEST_H
+
+/**
+ *
+ * MClientRequest - container for a client METADATA request. created/sent by clients.
+ * can be forwarded around between MDS's.
+ *
+ * int client - the originating client
+ * long tid - transaction id, unique among requests for that client. probably just a counter!
+ * -> the MDS passes the Request to the Reply constructor, so this always matches.
+ *
+ * int op - the metadata op code. MDS_OP_RENAME, etc.
+ * int caller_uid, _gid - guess
+ *
+ * fixed size arguments are in a union.
+ * there's also a string argument, for e.g. symlink().
+ *
+ */
+
+#include <string_view>
+
+#include "include/filepath.h"
+#include "mds/mdstypes.h"
+#include "include/ceph_features.h"
+#include "mds/cephfs_features.h"
+#include "messages/MMDSOp.h"
+
+#include <sys/types.h>
+#include <utime.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+struct SnapPayload {
+ std::map<std::string, std::string> metadata;
+
+ void encode(ceph::buffer::list &bl) const {
+ ENCODE_START(1, 1, bl);
+ encode(metadata, bl);
+ ENCODE_FINISH(bl);
+ }
+
+ void decode(ceph::buffer::list::const_iterator &iter) {
+ DECODE_START(1, iter);
+ decode(metadata, iter);
+ DECODE_FINISH(iter);
+ }
+};
+
+WRITE_CLASS_ENCODER(SnapPayload)
+
+// metadata ops.
+
+class MClientRequest final : public MMDSOp {
+private:
+ static constexpr int HEAD_VERSION = 6;
+ static constexpr int COMPAT_VERSION = 1;
+
+public:
+ mutable struct ceph_mds_request_head head; /* XXX HACK! */
+ utime_t stamp;
+ feature_bitset_t mds_features;
+
+ struct Release {
+ mutable ceph_mds_request_release item;
+ std::string dname;
+
+ Release() : item(), dname() {}
+ Release(const ceph_mds_request_release& rel, std::string name) :
+ item(rel), dname(name) {}
+
+ void encode(ceph::buffer::list& bl) const {
+ using ceph::encode;
+ item.dname_len = dname.length();
+ encode(item, bl);
+ ceph::encode_nohead(dname, bl);
+ }
+ void decode(ceph::buffer::list::const_iterator& bl) {
+ using ceph::decode;
+ decode(item, bl);
+ ceph::decode_nohead(item.dname_len, dname, bl);
+ }
+ };
+ mutable std::vector<Release> releases; /* XXX HACK! */
+
+ // path arguments
+ filepath path, path2;
+ std::string alternate_name;
+ std::vector<uint64_t> gid_list;
+
+ std::vector<uint8_t> fscrypt_auth;
+ std::vector<uint8_t> fscrypt_file;
+
+ /* XXX HACK */
+ mutable bool queued_for_replay = false;
+
+protected:
+ // cons
+ MClientRequest()
+ : MMDSOp(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) {
+ memset(&head, 0, sizeof(head));
+ head.owner_uid = -1;
+ head.owner_gid = -1;
+ }
+ MClientRequest(int op, feature_bitset_t features = 0)
+ : MMDSOp(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) {
+ memset(&head, 0, sizeof(head));
+ head.op = op;
+ mds_features = features;
+ head.owner_uid = -1;
+ head.owner_gid = -1;
+ }
+ ~MClientRequest() final {}
+
+public:
+ void set_mdsmap_epoch(epoch_t e) { head.mdsmap_epoch = e; }
+ epoch_t get_mdsmap_epoch() const { return head.mdsmap_epoch; }
+ epoch_t get_osdmap_epoch() const {
+ ceph_assert(head.op == CEPH_MDS_OP_SETXATTR);
+ if (header.version >= 3)
+ return head.args.setxattr.osdmap_epoch;
+ else
+ return 0;
+ }
+ void set_osdmap_epoch(epoch_t e) {
+ ceph_assert(head.op == CEPH_MDS_OP_SETXATTR);
+ head.args.setxattr.osdmap_epoch = e;
+ }
+
+ metareqid_t get_reqid() const {
+ // FIXME: for now, assume clients always have 1 incarnation
+ return metareqid_t(get_orig_source(), header.tid);
+ }
+
+ /*bool open_file_mode_is_readonly() {
+ return file_mode_is_readonly(ceph_flags_to_mode(head.args.open.flags));
+ }*/
+ bool may_write() const {
+ return
+ (head.op & CEPH_MDS_OP_WRITE) ||
+ (head.op == CEPH_MDS_OP_OPEN && (head.args.open.flags & (O_CREAT|O_TRUNC)));
+ }
+
+ int get_flags() const {
+ return head.flags;
+ }
+ bool is_replay() const {
+ return get_flags() & CEPH_MDS_FLAG_REPLAY;
+ }
+ bool is_async() const {
+ return get_flags() & CEPH_MDS_FLAG_ASYNC;
+ }
+
+ // normal fields
+ void set_stamp(utime_t t) { stamp = t; }
+ void set_oldest_client_tid(ceph_tid_t t) { head.oldest_client_tid = t; }
+ void inc_num_fwd() { head.ext_num_fwd = head.ext_num_fwd + 1; }
+ void set_retry_attempt(int a) { head.ext_num_retry = a; }
+ void set_filepath(const filepath& fp) { path = fp; }
+ void set_filepath2(const filepath& fp) { path2 = fp; }
+ void set_string2(const char *s) { path2.set_path(std::string_view(s), 0); }
+ void set_caller_uid(unsigned u) { head.caller_uid = u; }
+ void set_caller_gid(unsigned g) { head.caller_gid = g; }
+ void set_gid_list(int count, const gid_t *gids) {
+ gid_list.reserve(count);
+ for (int i = 0; i < count; ++i) {
+ gid_list.push_back(gids[i]);
+ }
+ }
+ void set_dentry_wanted() {
+ head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY;
+ }
+ void set_replayed_op() {
+ head.flags = head.flags | CEPH_MDS_FLAG_REPLAY;
+ }
+ void set_async_op() {
+ head.flags = head.flags | CEPH_MDS_FLAG_ASYNC;
+ }
+
+ void set_alternate_name(std::string _alternate_name) {
+ alternate_name = std::move(_alternate_name);
+ }
+ void set_alternate_name(bufferptr&& cipher) {
+ alternate_name = std::move(cipher.c_str());
+ }
+
+ utime_t get_stamp() const { return stamp; }
+ ceph_tid_t get_oldest_client_tid() const { return head.oldest_client_tid; }
+ int get_num_fwd() const { return head.ext_num_fwd; }
+ int get_retry_attempt() const { return head.ext_num_retry; }
+ int get_op() const { return head.op; }
+ unsigned get_caller_uid() const { return head.caller_uid; }
+ unsigned get_caller_gid() const { return head.caller_gid; }
+ unsigned get_owner_uid() const { return head.owner_uid; }
+ unsigned get_owner_gid() const { return head.owner_gid; }
+ const std::vector<uint64_t>& get_caller_gid_list() const { return gid_list; }
+
+ const std::string& get_path() const { return path.get_path(); }
+ const filepath& get_filepath() const { return path; }
+ const std::string& get_path2() const { return path2.get_path(); }
+ const filepath& get_filepath2() const { return path2; }
+ std::string_view get_alternate_name() const { return std::string_view(alternate_name); }
+
+ int get_dentry_wanted() const { return get_flags() & CEPH_MDS_FLAG_WANT_DENTRY; }
+
+ void mark_queued_for_replay() const { queued_for_replay = true; }
+ bool is_queued_for_replay() const { return queued_for_replay; }
+
+ void decode_payload() override {
+ using ceph::decode;
+ auto p = payload.cbegin();
+
+ if (header.version >= 4) {
+ decode(head, p);
+ } else {
+ struct ceph_mds_request_head_legacy old_mds_head;
+
+ decode(old_mds_head, p);
+ copy_from_legacy_head(&head, &old_mds_head);
+ head.version = 0;
+
+ head.ext_num_retry = head.num_retry;
+ head.ext_num_fwd = head.num_fwd;
+
+ head.owner_uid = head.caller_uid;
+ head.owner_gid = head.caller_gid;
+
+ /* Can't set the btime from legacy struct */
+ if (head.op == CEPH_MDS_OP_SETATTR) {
+ int localmask = head.args.setattr.mask;
+
+ localmask &= ~CEPH_SETATTR_BTIME;
+
+ head.args.setattr.btime = { ceph_le32(0), ceph_le32(0) };
+ head.args.setattr.mask = localmask;
+ }
+ }
+
+ decode(path, p);
+ decode(path2, p);
+ ceph::decode_nohead(head.num_releases, releases, p);
+ if (header.version >= 2)
+ decode(stamp, p);
+ if (header.version >= 4) // epoch 3 was for a ceph_mds_request_args change
+ decode(gid_list, p);
+ if (header.version >= 5)
+ decode(alternate_name, p);
+ if (header.version >= 6) {
+ decode(fscrypt_auth, p);
+ decode(fscrypt_file, p);
+ }
+ }
+
+ void encode_payload(uint64_t features) override {
+ using ceph::encode;
+ head.num_releases = releases.size();
+ /*
+ * If the peer is old version, we must skip all the
+ * new members, because the old version of MDS or
+ * client will just copy the 'head' memory and isn't
+ * that smart to skip them.
+ */
+ if (!mds_features.test(CEPHFS_FEATURE_32BITS_RETRY_FWD)) {
+ head.version = 1;
+ } else if (!mds_features.test(CEPHFS_FEATURE_HAS_OWNER_UIDGID)) {
+ head.version = 2;
+ } else {
+ head.version = CEPH_MDS_REQUEST_HEAD_VERSION;
+ }
+
+ if (features & CEPH_FEATURE_FS_BTIME) {
+ encode(head, payload);
+ } else {
+ struct ceph_mds_request_head_legacy old_mds_head;
+
+ copy_to_legacy_head(&old_mds_head, &head);
+ encode(old_mds_head, payload);
+ }
+
+ encode(path, payload);
+ encode(path2, payload);
+ ceph::encode_nohead(releases, payload);
+ encode(stamp, payload);
+ encode(gid_list, payload);
+ encode(alternate_name, payload);
+ encode(fscrypt_auth, payload);
+ encode(fscrypt_file, payload);
+ }
+
+ std::string_view get_type_name() const override { return "creq"; }
+ void print(std::ostream& out) const override {
+ out << "client_request(" << get_orig_source()
+ << ":" << get_tid()
+ << " " << ceph_mds_op_name(get_op());
+ if (IS_CEPH_MDS_OP_NEWINODE(head.op)) {
+ out << " owner_uid=" << head.owner_uid
+ << ", owner_gid=" << head.owner_gid;
+ }
+ if (head.op == CEPH_MDS_OP_GETATTR)
+ out << " " << ccap_string(head.args.getattr.mask);
+ if (head.op == CEPH_MDS_OP_SETATTR) {
+ if (head.args.setattr.mask & CEPH_SETATTR_MODE)
+ out << " mode=0" << std::oct << head.args.setattr.mode << std::dec;
+ if (head.args.setattr.mask & CEPH_SETATTR_UID)
+ out << " uid=" << head.args.setattr.uid;
+ if (head.args.setattr.mask & CEPH_SETATTR_GID)
+ out << " gid=" << head.args.setattr.gid;
+ if (head.args.setattr.mask & CEPH_SETATTR_SIZE)
+ out << " size=" << head.args.setattr.size;
+ if (head.args.setattr.mask & CEPH_SETATTR_MTIME)
+ out << " mtime=" << utime_t(head.args.setattr.mtime);
+ if (head.args.setattr.mask & CEPH_SETATTR_ATIME)
+ out << " atime=" << utime_t(head.args.setattr.atime);
+ }
+ if (head.op == CEPH_MDS_OP_SETFILELOCK ||
+ head.op == CEPH_MDS_OP_GETFILELOCK) {
+ out << " rule " << (int)head.args.filelock_change.rule
+ << ", type " << (int)head.args.filelock_change.type
+ << ", owner " << head.args.filelock_change.owner
+ << ", pid " << head.args.filelock_change.pid
+ << ", start " << head.args.filelock_change.start
+ << ", length " << head.args.filelock_change.length
+ << ", wait " << (int)head.args.filelock_change.wait;
+ }
+ //if (!get_filepath().empty())
+ out << " " << get_filepath();
+ if (alternate_name.size())
+ out << " (" << alternate_name << ") ";
+ if (!get_filepath2().empty())
+ out << " " << get_filepath2();
+ if (stamp != utime_t())
+ out << " " << stamp;
+ if (head.ext_num_fwd)
+ out << " FWD=" << (int)head.ext_num_fwd;
+ if (head.ext_num_retry)
+ out << " RETRY=" << (int)head.ext_num_retry;
+ if (is_async())
+ out << " ASYNC";
+ if (is_replay())
+ out << " REPLAY";
+ if (queued_for_replay)
+ out << " QUEUED_FOR_REPLAY";
+ out << " caller_uid=" << head.caller_uid
+ << ", caller_gid=" << head.caller_gid
+ << '{';
+ for (auto i = gid_list.begin(); i != gid_list.end(); ++i)
+ out << *i << ',';
+ out << '}'
+ << ")";
+ }
+private:
+ template<class T, typename... Args>
+ friend boost::intrusive_ptr<T> ceph::make_message(Args&&... args);
+ template<class T, typename... Args>
+ friend MURef<T> crimson::make_message(Args&&... args);
+};
+
+WRITE_CLASS_ENCODER(MClientRequest::Release)
+
+#endif