1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	
4    	#include "rbd_replay/ActionTypes.h"
5    	#include "include/ceph_assert.h"
6    	#include "include/byteorder.h"
7    	#include "include/stringify.h"
8    	#include "common/Formatter.h"
9    	#include <iostream>
10   	#include <boost/variant.hpp>
11   	
12   	namespace rbd_replay {
13   	namespace action {
14   	
15   	namespace {
16   	
17   	bool byte_swap_required(__u8 version) {
18   	#if defined(CEPH_LITTLE_ENDIAN)
19   	  return (version == 0);
20   	#else
21   	  return false;
22   	#endif
23   	}
24   	
25   	void decode_big_endian_string(std::string &str, bufferlist::const_iterator &it) {
26   	  using ceph::decode;
27   	#if defined(CEPH_LITTLE_ENDIAN)
28   	  uint32_t length;
29   	  decode(length, it);
30   	  length = swab(length);
31   	  str.clear();
32   	  it.copy(length, str);
33   	#else
34   	  ceph_abort();
35   	#endif
36   	}
37   	
38   	class EncodeVisitor : public boost::static_visitor<void> {
39   	public:
40   	  explicit EncodeVisitor(bufferlist &bl) : m_bl(bl) {
41   	  }
42   	
43   	  template <typename Action>
44   	  inline void operator()(const Action &action) const {
45   	    using ceph::encode;
(1) Event overrun-buffer-val: Overrunning buffer pointed to by "__u8 const(8)" of 1 bytes by passing it to a function which accesses it at byte offset 7. [details]
46   	    encode(static_cast<uint8_t>(Action::ACTION_TYPE), m_bl);
47   	    action.encode(m_bl);
48   	  }
49   	private:
50   	  bufferlist &m_bl;
51   	};
52   	
53   	class DecodeVisitor : public boost::static_visitor<void> {
54   	public:
55   	  DecodeVisitor(__u8 version, bufferlist::const_iterator &iter)
56   	    : m_version(version), m_iter(iter) {
57   	  }
58   	
59   	  template <typename Action>
60   	  inline void operator()(Action &action) const {
61   	    action.decode(m_version, m_iter);
62   	  }
63   	private:
64   	  __u8 m_version;
65   	  bufferlist::const_iterator &m_iter;
66   	};
67   	
68   	class DumpVisitor : public boost::static_visitor<void> {
69   	public:
70   	  explicit DumpVisitor(Formatter *formatter) : m_formatter(formatter) {}
71   	
72   	  template <typename Action>
73   	  inline void operator()(const Action &action) const {
74   	    ActionType action_type = Action::ACTION_TYPE;
75   	    m_formatter->dump_string("action_type", stringify(action_type));
76   	    action.dump(m_formatter);
77   	  }
78   	private:
79   	  ceph::Formatter *m_formatter;
80   	};
81   	
82   	} // anonymous namespace
83   	
84   	void Dependency::encode(bufferlist &bl) const {
85   	  using ceph::encode;
86   	  encode(id, bl);
87   	  encode(time_delta, bl);
88   	}
89   	
90   	void Dependency::decode(bufferlist::const_iterator &it) {
91   	  decode(1, it);
92   	}
93   	
94   	void Dependency::decode(__u8 version, bufferlist::const_iterator &it) {
95   	  using ceph::decode;
96   	  decode(id, it);
97   	  decode(time_delta, it);
98   	  if (byte_swap_required(version)) {
99   	    id = swab(id);
100  	    time_delta = swab(time_delta);
101  	  }
102  	}
103  	
104  	void Dependency::dump(Formatter *f) const {
105  	  f->dump_unsigned("id", id);
106  	  f->dump_unsigned("time_delta", time_delta);
107  	}
108  	
109  	void Dependency::generate_test_instances(std::list<Dependency *> &o) {
110  	  o.push_back(new Dependency());
111  	  o.push_back(new Dependency(1, 123456789));
112  	}
113  	
114  	void ActionBase::encode(bufferlist &bl) const {
115  	  using ceph::encode;
116  	  encode(id, bl);
117  	  encode(thread_id, bl);
118  	  encode(dependencies, bl);
119  	}
120  	
121  	void ActionBase::decode(__u8 version, bufferlist::const_iterator &it) {
122  	  using ceph::decode;
123  	  decode(id, it);
124  	  decode(thread_id, it);
125  	  if (version == 0) {
126  	    uint32_t num_successors;
127  	    decode(num_successors, it);
128  	
129  	    uint32_t num_completion_successors;
130  	    decode(num_completion_successors, it);
131  	  }
132  	
133  	  if (byte_swap_required(version)) {
134  	    id = swab(id);
135  	    thread_id = swab(thread_id);
136  	
137  	    uint32_t dep_count;
138  	    decode(dep_count, it);
139  	    dep_count = swab(dep_count);
140  	    dependencies.resize(dep_count);
141  	    for (uint32_t i = 0; i < dep_count; ++i) {
142  	      dependencies[i].decode(0, it);
143  	    }
144  	  } else {
145  	    decode(dependencies, it);
146  	  }
147  	}
148  	
149  	void ActionBase::dump(Formatter *f) const {
150  	  f->dump_unsigned("id", id);
151  	  f->dump_unsigned("thread_id", thread_id);
152  	  f->open_array_section("dependencies");
153  	  for (size_t i = 0; i < dependencies.size(); ++i) {
154  	    f->open_object_section("dependency");
155  	    dependencies[i].dump(f);
156  	    f->close_section();
157  	  }
158  	  f->close_section();
159  	}
160  	
161  	void ImageActionBase::encode(bufferlist &bl) const {
162  	  using ceph::encode;
163  	  ActionBase::encode(bl);
164  	  encode(imagectx_id, bl);
165  	}
166  	
167  	void ImageActionBase::decode(__u8 version, bufferlist::const_iterator &it) {
168  	  using ceph::decode;
169  	  ActionBase::decode(version, it);
170  	  decode(imagectx_id, it);
171  	  if (byte_swap_required(version)) {
172  	    imagectx_id = swab(imagectx_id);
173  	  }
174  	}
175  	
176  	void ImageActionBase::dump(Formatter *f) const {
177  	  ActionBase::dump(f);
178  	  f->dump_unsigned("imagectx_id", imagectx_id);
179  	}
180  	
181  	void IoActionBase::encode(bufferlist &bl) const {
182  	  using ceph::encode;
183  	  ImageActionBase::encode(bl);
184  	  encode(offset, bl);
185  	  encode(length, bl);
186  	}
187  	
188  	void IoActionBase::decode(__u8 version, bufferlist::const_iterator &it) {
189  	  using ceph::decode;
190  	  ImageActionBase::decode(version, it);
191  	  decode(offset, it);
192  	  decode(length, it);
193  	  if (byte_swap_required(version)) {
194  	    offset = swab(offset);
195  	    length = swab(length);
196  	  }
197  	}
198  	
199  	void IoActionBase::dump(Formatter *f) const {
200  	  ImageActionBase::dump(f);
201  	  f->dump_unsigned("offset", offset);
202  	  f->dump_unsigned("length", length);
203  	}
204  	
205  	void OpenImageAction::encode(bufferlist &bl) const {
206  	  using ceph::encode;
207  	  ImageActionBase::encode(bl);
208  	  encode(name, bl);
209  	  encode(snap_name, bl);
210  	  encode(read_only, bl);
211  	}
212  	
213  	void OpenImageAction::decode(__u8 version, bufferlist::const_iterator &it) {
214  	  using ceph::decode;
215  	  ImageActionBase::decode(version, it);
216  	  if (byte_swap_required(version)) {
217  	    decode_big_endian_string(name, it);
218  	    decode_big_endian_string(snap_name, it);
219  	  } else {
220  	    decode(name, it);
221  	    decode(snap_name, it);
222  	  }
223  	  decode(read_only, it);
224  	}
225  	
226  	void OpenImageAction::dump(Formatter *f) const {
227  	  ImageActionBase::dump(f);
228  	  f->dump_string("name", name);
229  	  f->dump_string("snap_name", snap_name);
230  	  f->dump_bool("read_only", read_only);
231  	}
232  	
233  	void AioOpenImageAction::encode(bufferlist &bl) const {
234  	  using ceph::encode;
235  	  ImageActionBase::encode(bl);
236  	  encode(name, bl);
237  	  encode(snap_name, bl);
238  	  encode(read_only, bl);
239  	}
240  	
241  	void AioOpenImageAction::decode(__u8 version, bufferlist::const_iterator &it) {
242  	  using ceph::decode;
243  	  ImageActionBase::decode(version, it);
244  	  if (byte_swap_required(version)) {
245  	    decode_big_endian_string(name, it);
246  	    decode_big_endian_string(snap_name, it);
247  	  } else {
248  	    decode(name, it);
249  	    decode(snap_name, it);
250  	  }
251  	  decode(read_only, it);
252  	}
253  	
254  	void AioOpenImageAction::dump(Formatter *f) const {
255  	  ImageActionBase::dump(f);
256  	  f->dump_string("name", name);
257  	  f->dump_string("snap_name", snap_name);
258  	  f->dump_bool("read_only", read_only);
259  	}
260  	
261  	void UnknownAction::encode(bufferlist &bl) const {
262  	  ceph_abort();
263  	}
264  	
265  	void UnknownAction::decode(__u8 version, bufferlist::const_iterator &it) {
266  	}
267  	
268  	void UnknownAction::dump(Formatter *f) const {
269  	}
270  	
271  	void ActionEntry::encode(bufferlist &bl) const {
272  	  ENCODE_START(1, 1, bl);
273  	  boost::apply_visitor(EncodeVisitor(bl), action);
274  	  ENCODE_FINISH(bl);
275  	}
276  	
277  	void ActionEntry::decode(bufferlist::const_iterator &it) {
278  	  DECODE_START(1, it);
279  	  decode_versioned(struct_v, it);
280  	  DECODE_FINISH(it);
281  	}
282  	
283  	void ActionEntry::decode_unversioned(bufferlist::const_iterator &it) {
284  	  decode_versioned(0, it);
285  	}
286  	
287  	void ActionEntry::decode_versioned(__u8 version, bufferlist::const_iterator &it) {
288  	  using ceph::decode;
289  	  uint8_t action_type;
290  	  decode(action_type, it);
291  	
292  	  // select the correct action variant based upon the action_type
293  	  switch (action_type) {
294  	  case ACTION_TYPE_START_THREAD:
295  	    action = StartThreadAction();
296  	    break;
297  	  case ACTION_TYPE_STOP_THREAD:
298  	    action = StopThreadAction();
299  	    break;
300  	  case ACTION_TYPE_READ:
301  	    action = ReadAction();
302  	    break;
303  	  case ACTION_TYPE_WRITE:
304  	    action = WriteAction();
305  	    break;
306  	  case ACTION_TYPE_DISCARD:
307  	    action = DiscardAction();
308  	    break;
309  	  case ACTION_TYPE_AIO_READ:
310  	    action = AioReadAction();
311  	    break;
312  	  case ACTION_TYPE_AIO_WRITE:
313  	    action = AioWriteAction();
314  	    break;
315  	  case ACTION_TYPE_AIO_DISCARD:
316  	    action = AioDiscardAction();
317  	    break;
318  	  case ACTION_TYPE_OPEN_IMAGE:
319  	    action = OpenImageAction();
320  	    break;
321  	  case ACTION_TYPE_CLOSE_IMAGE:
322  	    action = CloseImageAction();
323  	    break;
324  	  case ACTION_TYPE_AIO_OPEN_IMAGE:
325  	    action = AioOpenImageAction();
326  	    break;
327  	  case ACTION_TYPE_AIO_CLOSE_IMAGE:
328  	    action = AioCloseImageAction();
329  	    break;
330  	  }
331  	
332  	  boost::apply_visitor(DecodeVisitor(version, it), action);
333  	}
334  	
335  	void ActionEntry::dump(Formatter *f) const {
336  	  boost::apply_visitor(DumpVisitor(f), action);
337  	}
338  	
339  	void ActionEntry::generate_test_instances(std::list<ActionEntry *> &o) {
340  	  Dependencies dependencies;
341  	  dependencies.push_back(Dependency(3, 123456789));
342  	  dependencies.push_back(Dependency(4, 234567890));
343  	
344  	  o.push_back(new ActionEntry(StartThreadAction()));
345  	  o.push_back(new ActionEntry(StartThreadAction(1, 123456789, dependencies)));
346  	  o.push_back(new ActionEntry(StopThreadAction()));
347  	  o.push_back(new ActionEntry(StopThreadAction(1, 123456789, dependencies)));
348  	
349  	  o.push_back(new ActionEntry(ReadAction()));
350  	  o.push_back(new ActionEntry(ReadAction(1, 123456789, dependencies, 3, 4, 5)));
351  	  o.push_back(new ActionEntry(WriteAction()));
352  	  o.push_back(new ActionEntry(WriteAction(1, 123456789, dependencies, 3, 4,
353  	                                          5)));
354  	  o.push_back(new ActionEntry(DiscardAction()));
355  	  o.push_back(new ActionEntry(DiscardAction(1, 123456789, dependencies, 3, 4,
356  	                                            5)));
357  	  o.push_back(new ActionEntry(AioReadAction()));
358  	  o.push_back(new ActionEntry(AioReadAction(1, 123456789, dependencies, 3, 4,
359  	                                            5)));
360  	  o.push_back(new ActionEntry(AioWriteAction()));
361  	  o.push_back(new ActionEntry(AioWriteAction(1, 123456789, dependencies, 3, 4,
362  	                                             5)));
363  	  o.push_back(new ActionEntry(AioDiscardAction()));
364  	  o.push_back(new ActionEntry(AioDiscardAction(1, 123456789, dependencies, 3, 4,
365  	                                               5)));
366  	
367  	  o.push_back(new ActionEntry(OpenImageAction()));
368  	  o.push_back(new ActionEntry(OpenImageAction(1, 123456789, dependencies, 3,
369  	                                              "image_name", "snap_name",
370  	                                              true)));
371  	  o.push_back(new ActionEntry(CloseImageAction()));
372  	  o.push_back(new ActionEntry(CloseImageAction(1, 123456789, dependencies, 3)));
373  	
374  	  o.push_back(new ActionEntry(AioOpenImageAction()));
375  	  o.push_back(new ActionEntry(AioOpenImageAction(1, 123456789, dependencies, 3,
376  	                                              "image_name", "snap_name",
377  	                                              true)));
378  	  o.push_back(new ActionEntry(AioCloseImageAction()));
379  	  o.push_back(new ActionEntry(AioCloseImageAction(1, 123456789, dependencies, 3)));
380  	}
381  	
382  	std::ostream &operator<<(std::ostream &out,
383  	                         const ActionType &type) {
384  	  using namespace rbd_replay::action;
385  	
386  	  switch (type) {
387  	  case ACTION_TYPE_START_THREAD:
388  	    out << "StartThread";
389  	    break;
390  	  case ACTION_TYPE_STOP_THREAD:
391  	    out << "StopThread";
392  	    break;
393  	  case ACTION_TYPE_READ:
394  	    out << "Read";
395  	    break;
396  	  case ACTION_TYPE_WRITE:
397  	    out << "Write";
398  	    break;
399  	  case ACTION_TYPE_DISCARD:
400  	    out << "Discard";
401  	    break;
402  	  case ACTION_TYPE_AIO_READ:
403  	    out << "AioRead";
404  	    break;
405  	  case ACTION_TYPE_AIO_WRITE:
406  	    out << "AioWrite";
407  	    break;
408  	  case ACTION_TYPE_AIO_DISCARD:
409  	    out << "AioDiscard";
410  	    break;
411  	  case ACTION_TYPE_OPEN_IMAGE:
412  	    out << "OpenImage";
413  	    break;
414  	  case ACTION_TYPE_CLOSE_IMAGE:
415  	    out << "CloseImage";
416  	    break;
417  	  case ACTION_TYPE_AIO_OPEN_IMAGE:
418  	    out << "AioOpenImage";
419  	    break;
420  	  case ACTION_TYPE_AIO_CLOSE_IMAGE:
421  	    out << "AioCloseImage";
422  	    break;
423  	  default:
424  	    out << "Unknown (" << static_cast<uint32_t>(type) << ")";
425  	    break;
426  	  }
427  	  return out;
428  	}
429  	
430  	} // namespace action
431  	} // namespace rbd_replay
432