// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #ifndef CEPH_CLIENT_METAREQUEST_H #define CEPH_CLIENT_METAREQUEST_H #include "include/types.h" #include "include/xlist.h" #include "include/filepath.h" #include "mds/mdstypes.h" #include "InodeRef.h" #include "UserPerm.h" #include "messages/MClientRequest.h" #include "messages/MClientReply.h" class Dentry; class dir_result_t; struct MetaRequest { private: InodeRef _inode, _old_inode, _other_inode; Dentry *_dentry; //associated with path Dentry *_old_dentry; //associated with path2 int abort_rc; public: ceph::coarse_mono_time created = ceph::coarse_mono_clock::zero(); uint64_t tid; utime_t op_stamp; ceph_mds_request_head head; filepath path, path2; std::string alternate_name; bufferlist data; int inode_drop; //the inode caps this operation will drop int inode_unless; //unless we have these caps already int old_inode_drop, old_inode_unless; int dentry_drop, dentry_unless; int old_dentry_drop, old_dentry_unless; int other_inode_drop, other_inode_unless; vector cap_releases; int regetattr_mask; // getattr mask if i need to re-stat after a traceless reply utime_t sent_stamp; mds_rank_t mds; // who i am asking mds_rank_t resend_mds; // someone wants you to (re)send the request here bool send_to_auth; // must send to auth mds __u32 sent_on_mseq; // mseq at last submission of this request int num_fwd; // # of times i've been forwarded int retry_attempt; std::atomic ref = { 1 }; ceph::cref_t reply; // the reply bool kick; bool success; // readdir result dir_result_t *dirp; //possible responses bool got_unsafe; xlist::item item; xlist::item unsafe_item; xlist::item unsafe_dir_item; xlist::item unsafe_target_item; ceph::condition_variable *caller_cond; // who to take up ceph::condition_variable *dispatch_cond; // who to kick back list waitfor_safe; InodeRef target; UserPerm perms; explicit MetaRequest(int op) : _dentry(NULL), _old_dentry(NULL), abort_rc(0), tid(0), inode_drop(0), inode_unless(0), old_inode_drop(0), old_inode_unless(0), dentry_drop(0), dentry_unless(0), old_dentry_drop(0), old_dentry_unless(0), other_inode_drop(0), other_inode_unless(0), regetattr_mask(0), mds(-1), resend_mds(-1), send_to_auth(false), sent_on_mseq(0), num_fwd(0), retry_attempt(0), reply(0), kick(false), success(false), dirp(NULL), got_unsafe(false), item(this), unsafe_item(this), unsafe_dir_item(this), unsafe_target_item(this), caller_cond(0), dispatch_cond(0) { memset(&head, 0, sizeof(head)); head.op = op; } ~MetaRequest(); /** * Prematurely terminate the request, such that callers * to make_request will receive `rc` as their result. */ void abort(int rc) { ceph_assert(rc != 0); abort_rc = rc; } /** * Whether abort() has been called for this request */ inline bool aborted() const { return abort_rc != 0; } /** * Given that abort() has been called for this request, what `rc` was * passed into it? */ int get_abort_code() const { return abort_rc; } void set_inode(Inode *in) { _inode = in; } Inode *inode() { return _inode.get(); } void take_inode(InodeRef *out) { out->swap(_inode); } void set_old_inode(Inode *in) { _old_inode = in; } Inode *old_inode() { return _old_inode.get(); } void take_old_inode(InodeRef *out) { out->swap(_old_inode); } void set_other_inode(Inode *in) { _other_inode = in; } Inode *other_inode() { return _other_inode.get(); } void take_other_inode(InodeRef *out) { out->swap(_other_inode); } void set_dentry(Dentry *d); Dentry *dentry(); void set_old_dentry(Dentry *d); Dentry *old_dentry(); MetaRequest* get() { ref++; return this; } /// psuedo-private put method; use Client::put_request() bool _put() { int v = --ref; return v == 0; } // normal fields void set_tid(ceph_tid_t t) { tid = t; } void set_oldest_client_tid(ceph_tid_t t) { head.oldest_client_tid = t; } void inc_num_fwd() { head.num_fwd = head.num_fwd + 1; } void set_retry_attempt(int a) { head.num_retry = a; } void set_filepath(const filepath& fp) { path = fp; } void set_filepath2(const filepath& fp) { path2 = fp; } void set_alternate_name(std::string an) { alternate_name = an; } void set_string2(const char *s) { path2.set_path(std::string_view(s), 0); } void set_caller_perms(const UserPerm& _perms) { perms.shallow_copy(_perms); head.caller_uid = perms.uid(); head.caller_gid = perms.gid(); } uid_t get_uid() { return perms.uid(); } uid_t get_gid() { return perms.gid(); } void set_data(const bufferlist &d) { data = d; } void set_dentry_wanted() { head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY; } int get_op() { return head.op; } ceph_tid_t get_tid() { return tid; } filepath& get_filepath() { return path; } filepath& get_filepath2() { return path2; } bool is_write() { return (head.op & CEPH_MDS_OP_WRITE) || (head.op == CEPH_MDS_OP_OPEN && (head.args.open.flags & (O_CREAT|O_TRUNC))); } bool can_forward() { if ((head.op & CEPH_MDS_OP_WRITE) || head.op == CEPH_MDS_OP_OPEN) // do not forward _any_ open request. return false; return true; } bool auth_is_best(int issued) { if (send_to_auth) return true; /* Any write op ? */ if (head.op & CEPH_MDS_OP_WRITE) return true; switch (head.op) { case CEPH_MDS_OP_OPEN: case CEPH_MDS_OP_READDIR: return true; case CEPH_MDS_OP_GETATTR: /* * If any 'x' caps is issued we can just choose the auth MDS * instead of the random replica MDSes. Because only when the * Locker is in LOCK_EXEC state will the loner client could * get the 'x' caps. And if we send the getattr requests to * any replica MDS it must auth pin and tries to rdlock from * the auth MDS, and then the auth MDS need to do the Locker * state transition to LOCK_SYNC. And after that the lock state * will change back. * * This cost much when doing the Locker state transition and * usually will need to revoke caps from clients. * * And for the 'Xs' caps for getxattr we will also choose the * auth MDS, because the MDS side code is buggy due to setxattr * won't notify the replica MDSes when the values changed and * the replica MDS will return the old values. Though we will * fix it in MDS code, but this still makes sense for old ceph. */ if (((head.args.getattr.mask & CEPH_CAP_ANY_SHARED) && (issued & CEPH_CAP_ANY_EXCL)) || (head.args.getattr.mask & (CEPH_STAT_RSTAT | CEPH_STAT_CAP_XATTR))) return true; default: return false; } } void dump(Formatter *f) const; }; #endif