1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
2    	// vim: ts=8 sw=2 smarttab
3    	/*
4    	 * Ceph - scalable distributed file system
5    	 *
6    	 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
7    	 *
8    	 * This is free software; you can redistribute it and/or
9    	 * modify it under the terms of the GNU Lesser General Public
10   	 * License version 2.1, as published by the Free Software 
11   	 * Foundation.  See file COPYING.
12   	 * 
13   	 */
14   	
15   	
16   	#ifndef CEPH_MCLIENTREQUEST_H
17   	#define CEPH_MCLIENTREQUEST_H
18   	
19   	/**
20   	 *
21   	 * MClientRequest - container for a client METADATA request.  created/sent by clients.  
22   	 *    can be forwarded around between MDS's.
23   	 *
24   	 *   int client - the originating client
25   	 *   long tid   - transaction id, unique among requests for that client.  probably just a counter!
26   	 *                -> the MDS passes the Request to the Reply constructor, so this always matches.
27   	 *  
28   	 *   int op - the metadata op code.  MDS_OP_RENAME, etc.
29   	 *   int caller_uid, _gid - guess
30   	 * 
31   	 * fixed size arguments are in a union.
32   	 * there's also a string argument, for e.g. symlink().
33   	 *  
34   	 */
35   	
36   	#include <string_view>
37   	
38   	#include "msg/Message.h"
39   	#include "include/filepath.h"
40   	#include "mds/mdstypes.h"
41   	#include "include/ceph_features.h"
42   	
43   	#include <sys/types.h>
44   	#include <utime.h>
45   	#include <sys/stat.h>
46   	#include <fcntl.h>
47   	
48   	
49   	// metadata ops.
50   	
51   	class MClientRequest : public Message {
52   	private:
53   	  static constexpr int HEAD_VERSION = 4;
54   	  static constexpr int COMPAT_VERSION = 1;
55   	
56   	public:
57   	  mutable struct ceph_mds_request_head head; /* XXX HACK! */
58   	  utime_t stamp;
59   	
60   	  struct Release {
61   	    mutable ceph_mds_request_release item;
62   	    string dname;
63   	
64   	    Release() : item(), dname() {}
65   	    Release(const ceph_mds_request_release& rel, string name) :
66   	      item(rel), dname(name) {}
67   	
68   	    void encode(bufferlist& bl) const {
69   	      using ceph::encode;
70   	      item.dname_len = dname.length();
71   	      encode(item, bl);
72   	      encode_nohead(dname, bl);
73   	    }
74   	    void decode(bufferlist::const_iterator& bl) {
75   	      using ceph::decode;
76   	      decode(item, bl);
77   	      decode_nohead(item.dname_len, dname, bl);
78   	    }
79   	  };
80   	  mutable vector<Release> releases; /* XXX HACK! */
81   	
82   	  // path arguments
83   	  filepath path, path2;
84   	  vector<uint64_t> gid_list;
85   	
86   	  /* XXX HACK */
87   	  mutable bool queued_for_replay = false;
88   	
89   	protected:
90   	  // cons
91   	  MClientRequest()
(2) Event uninit_member: Non-static class member field "head.version" is not initialized in this constructor nor in any functions that it calls.
(4) Event uninit_member: Non-static class member field "head.oldest_client_tid" is not initialized in this constructor nor in any functions that it calls.
(6) Event uninit_member: Non-static class member field "head.mdsmap_epoch" is not initialized in this constructor nor in any functions that it calls.
(8) Event uninit_member: Non-static class member field "head.flags" is not initialized in this constructor nor in any functions that it calls.
(10) Event uninit_member: Non-static class member field "head.num_retry" is not initialized in this constructor nor in any functions that it calls.
(12) Event uninit_member: Non-static class member field "head.num_fwd" is not initialized in this constructor nor in any functions that it calls.
(14) Event uninit_member: Non-static class member field "head.num_releases" is not initialized in this constructor nor in any functions that it calls.
(16) Event uninit_member: Non-static class member field "head.op" is not initialized in this constructor nor in any functions that it calls.
(18) Event uninit_member: Non-static class member field "head.caller_uid" is not initialized in this constructor nor in any functions that it calls.
(20) Event uninit_member: Non-static class member field "head.caller_gid" is not initialized in this constructor nor in any functions that it calls.
(22) Event uninit_member: Non-static class member field "head.ino" is not initialized in this constructor nor in any functions that it calls.
Also see events: [member_decl][member_decl][member_decl][member_decl][member_decl][member_decl][member_decl][member_decl][member_decl][member_decl][member_decl]
92   	    : Message(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) {}
93   	  MClientRequest(int op)
94   	    : Message(CEPH_MSG_CLIENT_REQUEST, HEAD_VERSION, COMPAT_VERSION) {
95   	    memset(&head, 0, sizeof(head));
96   	    head.op = op;
97   	  }
98   	  ~MClientRequest() override {}
99   	
100  	public:
101  	  void set_mdsmap_epoch(epoch_t e) { head.mdsmap_epoch = e; }
102  	  epoch_t get_mdsmap_epoch() const { return head.mdsmap_epoch; }
103  	  epoch_t get_osdmap_epoch() const {
104  	    ceph_assert(head.op == CEPH_MDS_OP_SETXATTR);
105  	    if (header.version >= 3)
106  	      return head.args.setxattr.osdmap_epoch;
107  	    else
108  	      return 0;
109  	  }
110  	  void set_osdmap_epoch(epoch_t e) {
111  	    ceph_assert(head.op == CEPH_MDS_OP_SETXATTR);
112  	    head.args.setxattr.osdmap_epoch = e;
113  	  }
114  	
115  	  metareqid_t get_reqid() const {
116  	    // FIXME: for now, assume clients always have 1 incarnation
117  	    return metareqid_t(get_orig_source(), header.tid); 
118  	  }
119  	
120  	  /*bool open_file_mode_is_readonly() {
121  	    return file_mode_is_readonly(ceph_flags_to_mode(head.args.open.flags));
122  	    }*/
123  	  bool may_write() const {
124  	    return
125  	      (head.op & CEPH_MDS_OP_WRITE) || 
126  	      (head.op == CEPH_MDS_OP_OPEN && (head.args.open.flags & (O_CREAT|O_TRUNC)));
127  	  }
128  	
129  	  int get_flags() const {
130  	    return head.flags;
131  	  }
132  	  bool is_replay() const {
133  	    return get_flags() & CEPH_MDS_FLAG_REPLAY;
134  	  }
135  	
136  	  // normal fields
137  	  void set_stamp(utime_t t) { stamp = t; }
138  	  void set_oldest_client_tid(ceph_tid_t t) { head.oldest_client_tid = t; }
139  	  void inc_num_fwd() { head.num_fwd = head.num_fwd + 1; }
140  	  void set_retry_attempt(int a) { head.num_retry = a; }
141  	  void set_filepath(const filepath& fp) { path = fp; }
142  	  void set_filepath2(const filepath& fp) { path2 = fp; }
143  	  void set_string2(const char *s) { path2.set_path(std::string_view(s), 0); }
144  	  void set_caller_uid(unsigned u) { head.caller_uid = u; }
145  	  void set_caller_gid(unsigned g) { head.caller_gid = g; }
146  	  void set_gid_list(int count, const gid_t *gids) {
147  	    gid_list.reserve(count);
148  	    for (int i = 0; i < count; ++i) {
149  	      gid_list.push_back(gids[i]);
150  	    }
151  	  }
152  	  void set_dentry_wanted() {
153  	    head.flags = head.flags | CEPH_MDS_FLAG_WANT_DENTRY;
154  	  }
155  	  void set_replayed_op() {
156  	    head.flags = head.flags | CEPH_MDS_FLAG_REPLAY;
157  	  }
158  	
159  	  utime_t get_stamp() const { return stamp; }
160  	  ceph_tid_t get_oldest_client_tid() const { return head.oldest_client_tid; }
161  	  int get_num_fwd() const { return head.num_fwd; }
162  	  int get_retry_attempt() const { return head.num_retry; }
163  	  int get_op() const { return head.op; }
164  	  unsigned get_caller_uid() const { return head.caller_uid; }
165  	  unsigned get_caller_gid() const { return head.caller_gid; }
166  	  const vector<uint64_t>& get_caller_gid_list() const { return gid_list; }
167  	
168  	  const string& get_path() const { return path.get_path(); }
169  	  const filepath& get_filepath() const { return path; }
170  	  const string& get_path2() const { return path2.get_path(); }
171  	  const filepath& get_filepath2() const { return path2; }
172  	
173  	  int get_dentry_wanted() const { return get_flags() & CEPH_MDS_FLAG_WANT_DENTRY; }
174  	
175  	  void mark_queued_for_replay() const { queued_for_replay = true; }
176  	  bool is_queued_for_replay() const { return queued_for_replay; }
177  	
178  	  void decode_payload() override {
179  	    auto p = payload.cbegin();
180  	
181  	    if (header.version >= 4) {
182  	      decode(head, p);
183  	    } else {
184  	      struct ceph_mds_request_head_legacy old_mds_head;
185  	
186  	      decode(old_mds_head, p);
187  	      copy_from_legacy_head(&head, &old_mds_head);
188  	      head.version = 0;
189  	
190  	      /* Can't set the btime from legacy struct */
191  	      if (head.op == CEPH_MDS_OP_SETATTR) {
192  		int localmask = head.args.setattr.mask;
193  	
194  		localmask &= ~CEPH_SETATTR_BTIME;
195  	
196  		head.args.setattr.btime = { init_le32(0), init_le32(0) };
197  		head.args.setattr.mask = localmask;
198  	      }
199  	    }
200  	
201  	    decode(path, p);
202  	    decode(path2, p);
203  	    decode_nohead(head.num_releases, releases, p);
204  	    if (header.version >= 2)
205  	      decode(stamp, p);
206  	    if (header.version >= 4) // epoch 3 was for a ceph_mds_request_args change
207  	      decode(gid_list, p);
208  	  }
209  	
210  	  void encode_payload(uint64_t features) override {
211  	    using ceph::encode;
212  	    head.num_releases = releases.size();
213  	    head.version = CEPH_MDS_REQUEST_HEAD_VERSION;
214  	
215  	    if (features & CEPH_FEATURE_FS_BTIME) {
216  	      encode(head, payload);
217  	    } else {
218  	      struct ceph_mds_request_head_legacy old_mds_head;
219  	
220  	      copy_to_legacy_head(&old_mds_head, &head);
221  	      encode(old_mds_head, payload);
222  	    }
223  	
224  	    encode(path, payload);
225  	    encode(path2, payload);
226  	    encode_nohead(releases, payload);
227  	    encode(stamp, payload);
228  	    encode(gid_list, payload);
229  	  }
230  	
231  	  std::string_view get_type_name() const override { return "creq"; }
232  	  void print(ostream& out) const override {
233  	    out << "client_request(" << get_orig_source() 
234  		<< ":" << get_tid() 
235  		<< " " << ceph_mds_op_name(get_op());
236  	    if (head.op == CEPH_MDS_OP_GETATTR)
237  	      out << " " << ccap_string(head.args.getattr.mask);
238  	    if (head.op == CEPH_MDS_OP_SETATTR) {
239  	      if (head.args.setattr.mask & CEPH_SETATTR_MODE)
240  		out << " mode=0" << std::oct << head.args.setattr.mode << std::dec;
241  	      if (head.args.setattr.mask & CEPH_SETATTR_UID)
242  		out << " uid=" << head.args.setattr.uid;
243  	      if (head.args.setattr.mask & CEPH_SETATTR_GID)
244  		out << " gid=" << head.args.setattr.gid;
245  	      if (head.args.setattr.mask & CEPH_SETATTR_SIZE)
246  		out << " size=" << head.args.setattr.size;
247  	      if (head.args.setattr.mask & CEPH_SETATTR_MTIME)
248  		out << " mtime=" << utime_t(head.args.setattr.mtime);
249  	      if (head.args.setattr.mask & CEPH_SETATTR_ATIME)
250  		out << " atime=" << utime_t(head.args.setattr.atime);
251  	    }
252  	    if (head.op == CEPH_MDS_OP_SETFILELOCK ||
253  		head.op == CEPH_MDS_OP_GETFILELOCK) {
254  	      out << " rule " << (int)head.args.filelock_change.rule
255  		  << ", type " << (int)head.args.filelock_change.type
256  		  << ", owner " << head.args.filelock_change.owner
257  		  << ", pid " << head.args.filelock_change.pid
258  		  << ", start " << head.args.filelock_change.start
259  		  << ", length " << head.args.filelock_change.length
260  		  << ", wait " << (int)head.args.filelock_change.wait;
261  	    }
262  	    //if (!get_filepath().empty()) 
263  	    out << " " << get_filepath();
264  	    if (!get_filepath2().empty())
265  	      out << " " << get_filepath2();
266  	    if (stamp != utime_t())
267  	      out << " " << stamp;
268  	    if (head.num_retry)
269  	      out << " RETRY=" << (int)head.num_retry;
270  	    if (get_flags() & CEPH_MDS_FLAG_REPLAY)
271  	      out << " REPLAY";
272  	    if (queued_for_replay)
273  	      out << " QUEUED_FOR_REPLAY";
274  	    out << " caller_uid=" << head.caller_uid
275  		<< ", caller_gid=" << head.caller_gid
276  		<< '{';
277  	    for (auto i = gid_list.begin(); i != gid_list.end(); ++i)
278  	      out << *i << ',';
279  	    out << '}'
280  		<< ")";
281  	  }
282  	private:
283  	  template<class T, typename... Args>
284  	  friend boost::intrusive_ptr<T> ceph::make_message(Args&&... args);
285  	};
286  	
287  	WRITE_CLASS_ENCODER(MClientRequest::Release)
288  	
289  	#endif
290