1    	// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2    	// vim: ts=8 sw=2 smarttab
3    	
4    	#include "test/librados_test_stub/LibradosTestStub.h"
5    	#include "include/rados/librados.hpp"
6    	#include "include/stringify.h"
7    	#include "common/ceph_argparse.h"
8    	#include "common/ceph_context.h"
9    	#include "common/common_init.h"
10   	#include "common/config.h"
11   	#include "common/debug.h"
12   	#include "common/snap_types.h"
13   	#include "librados/AioCompletionImpl.h"
14   	#include "log/Log.h"
15   	#include "test/librados_test_stub/TestClassHandler.h"
16   	#include "test/librados_test_stub/TestIoCtxImpl.h"
17   	#include "test/librados_test_stub/TestRadosClient.h"
18   	#include "test/librados_test_stub/TestMemCluster.h"
19   	#include "test/librados_test_stub/TestMemRadosClient.h"
20   	#include "objclass/objclass.h"
21   	#include "osd/osd_types.h"
22   	#include <arpa/inet.h>
23   	#include <boost/bind.hpp>
24   	#include <boost/shared_ptr.hpp>
25   	#include <deque>
26   	#include <list>
27   	#include <vector>
28   	#include "include/ceph_assert.h"
29   	#include "include/compat.h"
30   	
31   	#define dout_context g_ceph_context
32   	#define dout_subsys ceph_subsys_rados
33   	
34   	namespace librados {
35   	
36   	MockTestMemIoCtxImpl &get_mock_io_ctx(IoCtx &ioctx) {
37   	  MockTestMemIoCtxImpl **mock =
38   	    reinterpret_cast<MockTestMemIoCtxImpl **>(&ioctx);
39   	  return **mock;
40   	}
41   	
42   	} // namespace librados
43   	
44   	namespace librados_test_stub {
45   	
46   	TestClusterRef &cluster() {
47   	  static TestClusterRef s_cluster;
48   	  return s_cluster;
49   	}
50   	
51   	void set_cluster(TestClusterRef cluster_ref) {
52   	  cluster() = cluster_ref;
53   	}
54   	
55   	TestClusterRef get_cluster() {
56   	  auto &cluster_ref = cluster();
57   	  if (cluster_ref.get() == nullptr) {
58   	    cluster_ref.reset(new librados::TestMemCluster());
59   	  }
60   	  return cluster_ref;
61   	}
62   	
63   	} // namespace librados_test_stub
64   	
65   	namespace {
66   	
67   	librados::TestClassHandler *get_class_handler() {
68   	  static boost::shared_ptr<librados::TestClassHandler> s_class_handler;
69   	  if (!s_class_handler) {
70   	    s_class_handler.reset(new librados::TestClassHandler());
71   	    s_class_handler->open_all_classes();
72   	  }
73   	  return s_class_handler.get();
74   	}
75   	
76   	void do_out_buffer(bufferlist& outbl, char **outbuf, size_t *outbuflen) {
77   	  if (outbuf) {
78   	    if (outbl.length() > 0) {
79   	      *outbuf = (char *)malloc(outbl.length());
80   	      memcpy(*outbuf, outbl.c_str(), outbl.length());
81   	    } else {
82   	      *outbuf = NULL;
83   	    }
84   	  }
85   	  if (outbuflen) {
86   	    *outbuflen = outbl.length();
87   	  }
88   	}
89   	
90   	void do_out_buffer(string& outbl, char **outbuf, size_t *outbuflen) {
91   	  if (outbuf) {
92   	    if (outbl.length() > 0) {
93   	      *outbuf = (char *)malloc(outbl.length());
94   	      memcpy(*outbuf, outbl.c_str(), outbl.length());
95   	    } else {
96   	      *outbuf = NULL;
97   	    }
98   	  }
99   	  if (outbuflen) {
100  	    *outbuflen = outbl.length();
101  	  }
102  	}
103  	
104  	librados::TestRadosClient *create_rados_client() {
105  	  CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT);
106  	  CephContext *cct = common_preinit(iparams, CODE_ENVIRONMENT_LIBRARY, 0);
107  	  cct->_conf.parse_env(cct->get_module_type());
108  	  cct->_conf.apply_changes(nullptr);
109  	  cct->_log->start();
110  	
111  	  auto rados_client =
112  	    librados_test_stub::get_cluster()->create_rados_client(cct);
113  	  cct->put();
114  	  return rados_client;
115  	}
116  	
117  	} // anonymous namespace
118  	
119  	extern "C" int rados_aio_create_completion(void *cb_arg,
120  	                                           rados_callback_t cb_complete,
121  	                                           rados_callback_t cb_safe,
122  	                                           rados_completion_t *pc)
123  	{
124  	  librados::AioCompletionImpl *c = new librados::AioCompletionImpl;
125  	  if (cb_complete) {
126  	    c->set_complete_callback(cb_arg, cb_complete);
127  	  }
128  	  if (cb_safe) {
129  	    c->set_safe_callback(cb_arg, cb_safe);
130  	  }
131  	  *pc = c;
132  	  return 0;
133  	}
134  	
135  	extern "C" int rados_aio_get_return_value(rados_completion_t c) {
136  	  return reinterpret_cast<librados::AioCompletionImpl*>(c)->get_return_value();
137  	}
138  	
139  	extern "C" rados_config_t rados_cct(rados_t cluster)
140  	{
141  	  librados::TestRadosClient *client =
142  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
143  	  return reinterpret_cast<rados_config_t>(client->cct());
144  	}
145  	
146  	extern "C" int rados_conf_set(rados_t cluster, const char *option,
147  	                              const char *value) {
148  	  librados::TestRadosClient *impl =
149  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
150  	  CephContext *cct = impl->cct();
151  	  return cct->_conf.set_val(option, value);
152  	}
153  	
154  	extern "C" int rados_conf_parse_env(rados_t cluster, const char *var) {
155  	  librados::TestRadosClient *client =
156  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
157  	  auto& conf = client->cct()->_conf;
158  	  conf.parse_env(client->cct()->get_module_type(), var);
159  	  conf.apply_changes(NULL);
160  	  return 0;
161  	}
162  	
163  	extern "C" int rados_conf_read_file(rados_t cluster, const char *path) {
164  	  librados::TestRadosClient *client =
165  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
166  	  auto& conf = client->cct()->_conf;
167  	  int ret = conf.parse_config_files(path, NULL, 0);
168  	  if (ret == 0) {
169  	    conf.parse_env(client->cct()->get_module_type());
170  	    conf.apply_changes(NULL);
171  	    conf.complain_about_parse_error(client->cct());
172  	  } else if (ret == -ENOENT) {
173  	    // ignore missing client config
174  	    return 0;
175  	  }
176  	  return ret;
177  	}
178  	
179  	extern "C" int rados_connect(rados_t cluster) {
180  	  librados::TestRadosClient *client =
181  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
182  	  return client->connect();
183  	}
184  	
185  	extern "C" int rados_create(rados_t *cluster, const char * const id) {
186  	  *cluster = create_rados_client();
187  	  return 0;
188  	}
189  	
190  	extern "C" int rados_create_with_context(rados_t *cluster,
191  	                                         rados_config_t cct_) {
192  	  auto cct = reinterpret_cast<CephContext*>(cct_);
193  	  *cluster = librados_test_stub::get_cluster()->create_rados_client(cct);
194  	  return 0;
195  	}
196  	
197  	extern "C" rados_config_t rados_ioctx_cct(rados_ioctx_t ioctx)
198  	{
199  	  librados::TestIoCtxImpl *ctx =
200  	    reinterpret_cast<librados::TestIoCtxImpl*>(ioctx);
201  	  return reinterpret_cast<rados_config_t>(ctx->get_rados_client()->cct());
202  	}
203  	
204  	extern "C" int rados_ioctx_create(rados_t cluster, const char *pool_name,
205  	                                  rados_ioctx_t *ioctx) {
206  	  librados::TestRadosClient *client =
207  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
208  	
209  	  int64_t pool_id = client->pool_lookup(pool_name);
210  	  if (pool_id < 0) {
211  	    return static_cast<int>(pool_id);
212  	  }
213  	
214  	  *ioctx = reinterpret_cast<rados_ioctx_t>(
215  	      client->create_ioctx(pool_id, pool_name));
216  	  return 0;
217  	}
218  	
219  	extern "C" int rados_ioctx_create2(rados_t cluster, int64_t pool_id,
220  	                                   rados_ioctx_t *ioctx)
221  	{
222  	  librados::TestRadosClient *client =
223  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
224  	
225  	  std::list<std::pair<int64_t, std::string> > pools;
226  	  int r = client->pool_list(pools);
227  	  if (r < 0) {
228  	    return r;
229  	  }
230  	
231  	  for (std::list<std::pair<int64_t, std::string> >::iterator it =
232  	       pools.begin(); it != pools.end(); ++it) {
233  	    if (it->first == pool_id) {
234  	      *ioctx = reinterpret_cast<rados_ioctx_t>(
235  		client->create_ioctx(pool_id, it->second));
236  	      return 0;
237  	    }
238  	  }
239  	  return -ENOENT;
240  	}
241  	
242  	extern "C" void rados_ioctx_destroy(rados_ioctx_t io) {
243  	  librados::TestIoCtxImpl *ctx =
244  	    reinterpret_cast<librados::TestIoCtxImpl*>(io);
245  	  ctx->put();
246  	}
247  	
248  	extern "C" rados_t rados_ioctx_get_cluster(rados_ioctx_t io) {
249  	  librados::TestIoCtxImpl *ctx =
250  	    reinterpret_cast<librados::TestIoCtxImpl*>(io);
251  	  return reinterpret_cast<rados_t>(ctx->get_rados_client());
252  	}
253  	
254  	extern "C" int rados_mon_command(rados_t cluster, const char **cmd,
255  	                                 size_t cmdlen, const char *inbuf,
256  	                                 size_t inbuflen, char **outbuf,
257  	                                 size_t *outbuflen, char **outs,
258  	                                 size_t *outslen) {
259  	  librados::TestRadosClient *client =
260  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
261  	
262  	  vector<string> cmdvec;
263  	  for (size_t i = 0; i < cmdlen; i++) {
264  	    cmdvec.push_back(cmd[i]);
265  	  }
266  	
267  	  bufferlist inbl;
268  	  inbl.append(inbuf, inbuflen);
269  	
270  	  bufferlist outbl;
271  	  string outstring;
272  	  int ret = client->mon_command(cmdvec, inbl, &outbl, &outstring);
273  	
274  	  do_out_buffer(outbl, outbuf, outbuflen);
275  	  do_out_buffer(outstring, outs, outslen);
276  	  return ret;
277  	}
278  	
279  	extern "C" int rados_nobjects_list_open(rados_ioctx_t io,
280  	                                        rados_list_ctx_t *ctx) {
281  	  librados::TestIoCtxImpl *io_ctx =
282  	    reinterpret_cast<librados::TestIoCtxImpl*>(io);
283  	  librados::TestRadosClient *client = io_ctx->get_rados_client();
284  	
285  	  std::list<librados::TestRadosClient::Object> *list =
286  	    new std::list<librados::TestRadosClient::Object>();
287  	  
288  	  client->object_list(io_ctx->get_id(), list);
289  	  list->push_front(librados::TestRadosClient::Object());
290  	  *ctx = reinterpret_cast<rados_list_ctx_t>(list);
291  	  return 0;
292  	}
293  	
294  	extern "C" int rados_nobjects_list_next(rados_list_ctx_t ctx,
295  	                                        const char **entry,
296  	                                        const char **key,
297  	                                        const char **nspace) {
298  	  std::list<librados::TestRadosClient::Object> *list =
299  	    reinterpret_cast<std::list<librados::TestRadosClient::Object> *>(ctx);
300  	  if (!list->empty()) {
301  	    list->pop_front();
302  	  }
303  	  if (list->empty()) {
304  	    return -ENOENT;
305  	  }
306  	
307  	  librados::TestRadosClient::Object &obj = list->front();
308  	  if (entry != NULL) {
309  	    *entry = obj.oid.c_str();
310  	  }
311  	  if (key != NULL) {
312  	    *key = obj.locator.c_str();
313  	  }
314  	  if (nspace != NULL) {
315  	    *nspace = obj.nspace.c_str();
316  	  }
317  	  return 0;
318  	}
319  	
320  	extern "C" void rados_nobjects_list_close(rados_list_ctx_t ctx) {
321  	  std::list<librados::TestRadosClient::Object> *list =
322  	    reinterpret_cast<std::list<librados::TestRadosClient::Object> *>(ctx);
323  	  delete list;
324  	}
325  	
326  	extern "C" int rados_pool_create(rados_t cluster, const char *pool_name) {
327  	  librados::TestRadosClient *client =
328  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
329  	  return client->pool_create(pool_name);
330  	}
331  	
332  	extern "C" int rados_pool_delete(rados_t cluster, const char *pool_name) {
333  	  librados::TestRadosClient *client =
334  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
335  	  return client->pool_delete(pool_name);
336  	}
337  	
338  	extern "C" void rados_shutdown(rados_t cluster) {
339  	  librados::TestRadosClient *client =
340  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
341  	  client->put();
342  	}
343  	
344  	extern "C" int rados_wait_for_latest_osdmap(rados_t cluster) {
345  	  librados::TestRadosClient *client =
346  	    reinterpret_cast<librados::TestRadosClient*>(cluster);
347  	  return client->wait_for_latest_osdmap();
348  	}
349  	
350  	namespace librados {
351  	
352  	void AioCompletion::release() {
353  	  AioCompletionImpl *c = reinterpret_cast<AioCompletionImpl *>(pc);
354  	  c->release();
355  	  delete this;
356  	}
357  	
358  	IoCtx::IoCtx() : io_ctx_impl(NULL) {
359  	}
360  	
361  	IoCtx::~IoCtx() {
362  	  close();
363  	}
364  	
365  	IoCtx::IoCtx(const IoCtx& rhs) {
366  	  io_ctx_impl = rhs.io_ctx_impl;
367  	  if (io_ctx_impl) {
368  	    TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
369  	    ctx->get();
370  	  }
371  	}
372  	
373  	IoCtx::IoCtx(IoCtx&& rhs) noexcept : io_ctx_impl(std::exchange(rhs.io_ctx_impl, nullptr))
374  	{
375  	}
376  	
377  	IoCtx& IoCtx::operator=(const IoCtx& rhs) {
378  	  if (io_ctx_impl) {
379  	    TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
380  	    ctx->put();
381  	  }
382  	
383  	  io_ctx_impl = rhs.io_ctx_impl;
384  	  if (io_ctx_impl) {
385  	    TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
386  	    ctx->get();
387  	  }
388  	  return *this;
389  	}
390  	
391  	librados::IoCtx& librados::IoCtx::operator=(IoCtx&& rhs) noexcept
392  	{
393  	  if (io_ctx_impl) {
394  	    TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
395  	    ctx->put();
396  	  }
397  	
398  	  io_ctx_impl = std::exchange(rhs.io_ctx_impl, nullptr);
399  	  return *this;
400  	}
401  	
402  	int IoCtx::aio_flush() {
403  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
404  	  ctx->aio_flush();
405  	  return 0;
406  	}
407  	
408  	int IoCtx::aio_flush_async(AioCompletion *c) {
409  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
410  	  ctx->aio_flush_async(c->pc);
411  	  return 0;
412  	}
413  	
414  	int IoCtx::aio_notify(const std::string& oid, AioCompletion *c, bufferlist& bl,
415  	                      uint64_t timeout_ms, bufferlist *pbl) {
416  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
417  	  ctx->aio_notify(oid, c->pc, bl, timeout_ms, pbl);
418  	  return 0;
419  	}
420  	
421  	int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
422  	                       ObjectReadOperation *op, bufferlist *pbl) {
423  	  return aio_operate(oid, c, op, 0, pbl);
424  	}
425  	
426  	int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
427  	                       ObjectReadOperation *op, int flags,
428  	                       bufferlist *pbl) {
429  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
430  	  TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
431  	  return ctx->aio_operate_read(oid, *ops, c->pc, flags, pbl);
432  	}
433  	
434  	int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
435  	                       ObjectReadOperation *op, int flags,
436  	                       bufferlist *pbl, const blkin_trace_info *trace_info) {
437  	  return aio_operate(oid, c, op, flags, pbl);
438  	}
439  	
440  	int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
441  	                       ObjectWriteOperation *op) {
442  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
443  	  TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
444  	  return ctx->aio_operate(oid, *ops, c->pc, NULL, 0);
445  	}
446  	
447  	int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
448  	                       ObjectWriteOperation *op, snap_t seq,
449  	                       std::vector<snap_t>& snaps, int flags,
450  	                       const blkin_trace_info *trace_info) {
451  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
452  	  TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
453  	
454  	  std::vector<snapid_t> snv;
455  	  snv.resize(snaps.size());
456  	  for (size_t i = 0; i < snaps.size(); ++i)
457  	    snv[i] = snaps[i];
458  	  SnapContext snapc(seq, snv);
459  	
460  	  return ctx->aio_operate(oid, *ops, c->pc, &snapc, flags);
461  	}
462  	
463  	int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
464  	                       ObjectWriteOperation *op, snap_t seq,
465  	                       std::vector<snap_t>& snaps) {
466  	  return aio_operate(oid, c, op, seq, snaps, 0, nullptr);
467  	}
468  	
469  	int IoCtx::aio_operate(const std::string& oid, AioCompletion *c,
470  	                       ObjectWriteOperation *op, snap_t seq,
471  	                       std::vector<snap_t>& snaps,
472  			       const blkin_trace_info *trace_info) {
473  	  return aio_operate(oid, c, op, seq, snaps, 0, trace_info);
474  	}
475  	
476  	int IoCtx::aio_remove(const std::string& oid, AioCompletion *c) {
477  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
478  	  return ctx->aio_remove(oid, c->pc);
479  	}
480  	
481  	int IoCtx::aio_remove(const std::string& oid, AioCompletion *c, int flags) {
482  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
483  	  return ctx->aio_remove(oid, c->pc, flags);
484  	}
485  	
486  	int IoCtx::aio_watch(const std::string& o, AioCompletion *c, uint64_t *handle,
487  	                     librados::WatchCtx2 *watch_ctx) {
488  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
489  	  return ctx->aio_watch(o, c->pc, handle, watch_ctx);
490  	}
491  	
492  	int IoCtx::aio_unwatch(uint64_t handle, AioCompletion *c) {
493  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
494  	  return ctx->aio_unwatch(handle, c->pc);
495  	}
496  	
497  	config_t IoCtx::cct() {
498  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
499  	  return reinterpret_cast<config_t>(ctx->get_rados_client()->cct());
500  	}
501  	
502  	void IoCtx::close() {
503  	  if (io_ctx_impl) {
504  	    TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
505  	    ctx->put();
506  	  }
507  	  io_ctx_impl = NULL;
508  	}
509  	
510  	int IoCtx::create(const std::string& oid, bool exclusive) {
511  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
512  	  return ctx->execute_operation(
513  	    oid, boost::bind(&TestIoCtxImpl::create, _1, _2, exclusive,
514  	                     ctx->get_snap_context()));
515  	}
516  	
517  	void IoCtx::dup(const IoCtx& rhs) {
518  	  close();
519  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(rhs.io_ctx_impl);
520  	  io_ctx_impl = reinterpret_cast<IoCtxImpl*>(ctx->clone());
521  	}
522  	
523  	int IoCtx::exec(const std::string& oid, const char *cls, const char *method,
524  	                bufferlist& inbl, bufferlist& outbl) {
525  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
526  	  return ctx->execute_operation(
527  	    oid, boost::bind(&TestIoCtxImpl::exec, _1, _2, get_class_handler(), cls,
528  	                     method, inbl, &outbl, ctx->get_snap_context()));
529  	}
530  	
531  	void IoCtx::from_rados_ioctx_t(rados_ioctx_t p, IoCtx &io) {
532  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(p);
533  	  ctx->get();
534  	
535  	  io.close();
536  	  io.io_ctx_impl = reinterpret_cast<IoCtxImpl*>(ctx);
537  	}
538  	
539  	uint64_t IoCtx::get_instance_id() const {
540  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
541  	  return ctx->get_instance_id();
542  	}
543  	
544  	int64_t IoCtx::get_id() {
545  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
546  	  return ctx->get_id();
547  	}
548  	
549  	uint64_t IoCtx::get_last_version() {
550  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
551  	  return ctx->get_last_version();
552  	}
553  	
554  	std::string IoCtx::get_pool_name() {
555  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
556  	  return ctx->get_pool_name();
557  	}
558  	
559  	int IoCtx::list_snaps(const std::string& o, snap_set_t *out_snaps) {
560  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
561  	  return ctx->execute_operation(
562  	    o, boost::bind(&TestIoCtxImpl::list_snaps, _1, _2, out_snaps));
563  	}
564  	
565  	int IoCtx::list_watchers(const std::string& o,
566  	                         std::list<obj_watch_t> *out_watchers) {
567  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
568  	  return ctx->execute_operation(
569  	    o, boost::bind(&TestIoCtxImpl::list_watchers, _1, _2, out_watchers));
570  	}
571  	
572  	int IoCtx::notify(const std::string& o, uint64_t ver, bufferlist& bl) {
573  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
574  	  return ctx->notify(o, bl, 0, NULL);
575  	}
576  	
577  	int IoCtx::notify2(const std::string& o, bufferlist& bl,
578  	                   uint64_t timeout_ms, bufferlist *pbl) {
579  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
580  	  return ctx->notify(o, bl, timeout_ms, pbl);
581  	}
582  	
583  	void IoCtx::notify_ack(const std::string& o, uint64_t notify_id,
584  	                       uint64_t handle, bufferlist& bl) {
585  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
586  	  ctx->notify_ack(o, notify_id, handle, bl);
587  	}
588  	
589  	int IoCtx::omap_get_vals(const std::string& oid,
590  	                         const std::string& start_after,
591  	                         uint64_t max_return,
592  	                         std::map<std::string, bufferlist> *out_vals) {
593  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
594  	  return ctx->execute_operation(
595  	    oid, boost::bind(&TestIoCtxImpl::omap_get_vals, _1, _2, start_after, "",
596  	                     max_return, out_vals));
597  	}
598  	
599  	int IoCtx::operate(const std::string& oid, ObjectWriteOperation *op) {
600  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
601  	  TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
602  	  return ctx->operate(oid, *ops);
603  	}
604  	
605  	int IoCtx::operate(const std::string& oid, ObjectReadOperation *op,
606  	                   bufferlist *pbl) {
607  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
608  	  TestObjectOperationImpl *ops = reinterpret_cast<TestObjectOperationImpl*>(op->impl);
609  	  return ctx->operate_read(oid, *ops, pbl);
610  	}
611  	
612  	int IoCtx::read(const std::string& oid, bufferlist& bl, size_t len,
613  	                uint64_t off) {
614  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
615  	  return ctx->execute_operation(
616  	    oid, boost::bind(&TestIoCtxImpl::read, _1, _2, len, off, &bl));
617  	}
618  	
619  	int IoCtx::remove(const std::string& oid) {
620  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
621  	  return ctx->execute_operation(
622  	    oid, boost::bind(&TestIoCtxImpl::remove, _1, _2, ctx->get_snap_context()));
623  	}
624  	
625  	int IoCtx::selfmanaged_snap_create(uint64_t *snapid) {
626  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
627  	  return ctx->selfmanaged_snap_create(snapid);
628  	}
629  	
630  	void IoCtx::aio_selfmanaged_snap_create(uint64_t *snapid, AioCompletion* c) {
631  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
632  	  return ctx->aio_selfmanaged_snap_create(snapid, c->pc);
633  	}
634  	
635  	int IoCtx::selfmanaged_snap_remove(uint64_t snapid) {
636  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
637  	  return ctx->selfmanaged_snap_remove(snapid);
638  	}
639  	
640  	void IoCtx::aio_selfmanaged_snap_remove(uint64_t snapid, AioCompletion* c) {
641  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
642  	  ctx->aio_selfmanaged_snap_remove(snapid, c->pc);
643  	}
644  	
645  	int IoCtx::selfmanaged_snap_rollback(const std::string& oid,
646  	                                     uint64_t snapid) {
647  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
648  	  return ctx->selfmanaged_snap_rollback(oid, snapid);
649  	}
650  	
651  	int IoCtx::selfmanaged_snap_set_write_ctx(snap_t seq,
652  	                                          std::vector<snap_t>& snaps) {
653  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
654  	  return ctx->selfmanaged_snap_set_write_ctx(seq, snaps);
655  	}
656  	
657  	void IoCtx::snap_set_read(snap_t seq) {
658  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
659  	  ctx->set_snap_read(seq);
660  	}
661  	
662  	int IoCtx::sparse_read(const std::string& oid, std::map<uint64_t,uint64_t>& m,
663  	                       bufferlist& bl, size_t len, uint64_t off) {
664  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
665  	  return ctx->execute_operation(
666  	    oid, boost::bind(&TestIoCtxImpl::sparse_read, _1, _2, off, len, &m, &bl));
667  	}
668  	
669  	int IoCtx::stat(const std::string& oid, uint64_t *psize, time_t *pmtime) {
670  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
671  	  return ctx->execute_operation(
672  	    oid, boost::bind(&TestIoCtxImpl::stat, _1, _2, psize, pmtime));
673  	}
674  	
675  	int IoCtx::tmap_update(const std::string& oid, bufferlist& cmdbl) {
676  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
677  	  return ctx->execute_operation(
678  	    oid, boost::bind(&TestIoCtxImpl::tmap_update, _1, _2, cmdbl));
679  	}
680  	
681  	int IoCtx::trunc(const std::string& oid, uint64_t off) {
682  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
683  	  return ctx->execute_operation(
684  	    oid, boost::bind(&TestIoCtxImpl::truncate, _1, _2, off,
685  	                     ctx->get_snap_context()));
686  	}
687  	
688  	int IoCtx::unwatch2(uint64_t handle) {
689  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
690  	  return ctx->unwatch(handle);
691  	}
692  	
693  	int IoCtx::unwatch(const std::string& o, uint64_t handle) {
694  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
695  	  return ctx->unwatch(handle);
696  	}
697  	
698  	int IoCtx::watch(const std::string& o, uint64_t ver, uint64_t *handle,
699  	                 librados::WatchCtx *wctx) {
700  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
701  	  return ctx->watch(o, handle, wctx, NULL);
702  	}
703  	
704  	int IoCtx::watch2(const std::string& o, uint64_t *handle,
705  	                  librados::WatchCtx2 *wctx) {
706  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
707  	  return ctx->watch(o, handle, NULL, wctx);
708  	}
709  	
710  	int IoCtx::write(const std::string& oid, bufferlist& bl, size_t len,
711  	                 uint64_t off) {
712  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
713  	  return ctx->execute_operation(
714  	    oid, boost::bind(&TestIoCtxImpl::write, _1, _2, bl, len, off,
715  	                     ctx->get_snap_context()));
716  	}
717  	
718  	int IoCtx::write_full(const std::string& oid, bufferlist& bl) {
719  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
720  	  return ctx->execute_operation(
721  	    oid, boost::bind(&TestIoCtxImpl::write_full, _1, _2, bl,
722  	                     ctx->get_snap_context()));
723  	}
724  	
725  	int IoCtx::writesame(const std::string& oid, bufferlist& bl, size_t len,
726  	                     uint64_t off) {
727  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
728  	  return ctx->execute_operation(
729  	    oid, boost::bind(&TestIoCtxImpl::writesame, _1, _2, bl, len, off,
730  	                     ctx->get_snap_context()));
731  	}
732  	
733  	int IoCtx::cmpext(const std::string& oid, uint64_t off, bufferlist& cmp_bl) {
734  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
735  	  return ctx->execute_operation(
736  	    oid, boost::bind(&TestIoCtxImpl::cmpext, _1, _2, off, cmp_bl));
737  	}
738  	
739  	int IoCtx::application_enable(const std::string& app_name, bool force) {
740  	  return 0;
741  	}
742  	
743  	int IoCtx::application_enable_async(const std::string& app_name,
744  	                                    bool force, PoolAsyncCompletion *c) {
745  	  return -EOPNOTSUPP;
746  	}
747  	
748  	int IoCtx::application_list(std::set<std::string> *app_names) {
749  	  return -EOPNOTSUPP;
750  	}
751  	
752  	int IoCtx::application_metadata_get(const std::string& app_name,
753  	                                    const std::string &key,
754  	                                    std::string *value) {
755  	  return -EOPNOTSUPP;
756  	}
757  	
758  	int IoCtx::application_metadata_set(const std::string& app_name,
759  	                                    const std::string &key,
760  	                                    const std::string& value) {
761  	  return -EOPNOTSUPP;
762  	}
763  	
764  	int IoCtx::application_metadata_remove(const std::string& app_name,
765  	                                       const std::string &key) {
766  	  return -EOPNOTSUPP;
767  	}
768  	
769  	int IoCtx::application_metadata_list(const std::string& app_name,
770  	                                     std::map<std::string, std::string> *values) {
771  	  return -EOPNOTSUPP;
772  	}
773  	
774  	void IoCtx::set_namespace(const std::string& nspace) {
775  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
776  	  ctx->set_namespace(nspace);
777  	}
778  	
779  	std::string IoCtx::get_namespace() const {
780  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(io_ctx_impl);
781  	  return ctx->get_namespace();
782  	}
783  	
784  	static int save_operation_result(int result, int *pval) {
785  	  if (pval != NULL) {
786  	    *pval = result;
787  	  }
788  	  return result;
789  	}
790  	
791  	ObjectOperation::ObjectOperation() {
792  	  TestObjectOperationImpl *o = new TestObjectOperationImpl();
793  	  o->get();
794  	  impl = reinterpret_cast<ObjectOperationImpl*>(o);
795  	}
796  	
797  	ObjectOperation::~ObjectOperation() {
798  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
799  	  if (o) {
800  	    o->put();
801  	    o = NULL;
802  	  }
803  	}
804  	
805  	void ObjectOperation::assert_exists() {
806  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
807  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::assert_exists, _1, _2));
808  	}
809  	
810  	void ObjectOperation::exec(const char *cls, const char *method,
811  	                           bufferlist& inbl) {
812  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
813  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::exec, _1, _2,
814  				       get_class_handler(), cls, method, inbl, _3, _4));
815  	}
816  	
817  	void ObjectOperation::set_op_flags2(int flags) {
818  	}
819  	
820  	size_t ObjectOperation::size() {
821  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
822  	  return o->ops.size();
823  	}
824  	
825  	void ObjectOperation::cmpext(uint64_t off, const bufferlist& cmp_bl,
826  	                             int *prval) {
827  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
828  	  ObjectOperationTestImpl op = boost::bind(&TestIoCtxImpl::cmpext, _1, _2, off, cmp_bl);
829  	  if (prval != NULL) {
830  	    op = boost::bind(save_operation_result,
831  	                     boost::bind(op, _1, _2, _3, _4), prval);
832  	  }
833  	  o->ops.push_back(op);
834  	}
835  	
836  	void ObjectReadOperation::list_snaps(snap_set_t *out_snaps, int *prval) {
837  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
838  	
839  	  ObjectOperationTestImpl op = boost::bind(&TestIoCtxImpl::list_snaps, _1, _2,
840  	                                           out_snaps);
841  	  if (prval != NULL) {
842  	    op = boost::bind(save_operation_result,
843  	                     boost::bind(op, _1, _2, _3, _4), prval);
844  	  }
845  	  o->ops.push_back(op);
846  	}
847  	
848  	void ObjectReadOperation::list_watchers(std::list<obj_watch_t> *out_watchers,
849  	                                        int *prval) {
850  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
851  	
852  	  ObjectOperationTestImpl op = boost::bind(&TestIoCtxImpl::list_watchers, _1,
853  	                                           _2, out_watchers);
854  	  if (prval != NULL) {
855  	    op = boost::bind(save_operation_result,
856  	                     boost::bind(op, _1, _2, _3, _4), prval);
857  	  }
858  	  o->ops.push_back(op);
859  	}
860  	
861  	void ObjectReadOperation::read(size_t off, uint64_t len, bufferlist *pbl,
862  	                               int *prval) {
863  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
864  	
865  	  ObjectOperationTestImpl op;
866  	  if (pbl != NULL) {
867  	    op = boost::bind(&TestIoCtxImpl::read, _1, _2, len, off, pbl);
868  	  } else {
869  	    op = boost::bind(&TestIoCtxImpl::read, _1, _2, len, off, _3);
870  	  }
871  	
872  	  if (prval != NULL) {
873  	    op = boost::bind(save_operation_result,
874  	                     boost::bind(op, _1, _2, _3, _4), prval);
875  	  }
876  	  o->ops.push_back(op);
877  	}
878  	
879  	void ObjectReadOperation::sparse_read(uint64_t off, uint64_t len,
880  	                                      std::map<uint64_t,uint64_t> *m,
881  	                                      bufferlist *pbl, int *prval) {
882  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
883  	
884  	  ObjectOperationTestImpl op;
885  	  if (pbl != NULL) {
886  	    op = boost::bind(&TestIoCtxImpl::sparse_read, _1, _2, off, len, m, pbl);
887  	  } else {
888  	    op = boost::bind(&TestIoCtxImpl::sparse_read, _1, _2, off, len, m, _3);
889  	  }
890  	
891  	  if (prval != NULL) {
892  	    op = boost::bind(save_operation_result,
893  	                     boost::bind(op, _1, _2, _3, _4), prval);
894  	  }
895  	  o->ops.push_back(op);
896  	}
897  	
898  	void ObjectReadOperation::stat(uint64_t *psize, time_t *pmtime, int *prval) {
899  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
900  	
901  	  ObjectOperationTestImpl op = boost::bind(&TestIoCtxImpl::stat, _1, _2,
902  	                                           psize, pmtime);
903  	
904  	  if (prval != NULL) {
905  	    op = boost::bind(save_operation_result,
906  	                     boost::bind(op, _1, _2, _3, _4), prval);
907  	  }
908  	  o->ops.push_back(op);
909  	}
910  	
911  	void ObjectWriteOperation::append(const bufferlist &bl) {
912  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
913  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::append, _1, _2, bl, _4));
914  	}
915  	
916  	void ObjectWriteOperation::create(bool exclusive) {
917  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
918  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::create, _1, _2, exclusive, _4));
919  	}
920  	
921  	void ObjectWriteOperation::omap_set(const std::map<std::string, bufferlist> &map) {
922  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
923  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::omap_set, _1, _2, boost::ref(map)));
924  	}
925  	
926  	void ObjectWriteOperation::remove() {
927  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
928  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::remove, _1, _2, _4));
929  	}
930  	
931  	void ObjectWriteOperation::selfmanaged_snap_rollback(uint64_t snapid) {
932  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
933  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::selfmanaged_snap_rollback,
934  				       _1, _2, snapid));
935  	}
936  	
937  	void ObjectWriteOperation::set_alloc_hint(uint64_t expected_object_size,
938  	                                          uint64_t expected_write_size) {
939  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
940  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::set_alloc_hint, _1, _2,
941  				       expected_object_size, expected_write_size, _4));
942  	}
943  	
944  	
945  	void ObjectWriteOperation::tmap_update(const bufferlist& cmdbl) {
946  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
947  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::tmap_update, _1, _2,
948  	                               cmdbl));
949  	}
950  	
951  	void ObjectWriteOperation::truncate(uint64_t off) {
952  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
953  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::truncate, _1, _2, off, _4));
954  	}
955  	
956  	void ObjectWriteOperation::write(uint64_t off, const bufferlist& bl) {
957  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
958  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::write, _1, _2, bl, bl.length(),
959  				       off, _4));
960  	}
961  	
962  	void ObjectWriteOperation::write_full(const bufferlist& bl) {
963  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
964  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::write_full, _1, _2, bl, _4));
965  	}
966  	
967  	void ObjectWriteOperation::writesame(uint64_t off, uint64_t len, const bufferlist& bl) {
968  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
969  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::writesame, _1, _2, bl, len,
970  				       off, _4));
971  	}
972  	
973  	void ObjectWriteOperation::zero(uint64_t off, uint64_t len) {
974  	  TestObjectOperationImpl *o = reinterpret_cast<TestObjectOperationImpl*>(impl);
975  	  o->ops.push_back(boost::bind(&TestIoCtxImpl::zero, _1, _2, off, len, _4));
976  	}
977  	
978  	Rados::Rados() : client(NULL) {
979  	}
980  	
981  	Rados::Rados(IoCtx& ioctx) {
982  	  TestIoCtxImpl *ctx = reinterpret_cast<TestIoCtxImpl*>(ioctx.io_ctx_impl);
983  	  TestRadosClient *impl = ctx->get_rados_client();
984  	  impl->get();
985  	
986  	  client = reinterpret_cast<RadosClient*>(impl);
987  	  ceph_assert(client != NULL);
988  	}
989  	
990  	Rados::~Rados() {
991  	  shutdown();
992  	}
993  	
994  	void Rados::from_rados_t(rados_t p, Rados &rados) {
995  	  if (rados.client != nullptr) {
996  	    reinterpret_cast<TestRadosClient*>(rados.client)->put();
997  	    rados.client = nullptr;
998  	  }
999  	
1000 	  auto impl = reinterpret_cast<TestRadosClient*>(p);
1001 	  if (impl) {
1002 	    impl->get();
1003 	    rados.client = reinterpret_cast<RadosClient*>(impl);
1004 	  }
1005 	}
1006 	
1007 	AioCompletion *Rados::aio_create_completion(void *cb_arg,
1008 	                                            callback_t cb_complete,
1009 	                                            callback_t cb_safe) {
1010 	  AioCompletionImpl *c;
1011 	  int r = rados_aio_create_completion(cb_arg, cb_complete, cb_safe,
1012 	      reinterpret_cast<void**>(&c));
1013 	  ceph_assert(r == 0);
1014 	  return new AioCompletion(c);
1015 	}
1016 	
1017 	int Rados::aio_watch_flush(AioCompletion* c) {
1018 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1019 	  return impl->aio_watch_flush(c->pc);
1020 	}
1021 	
1022 	int Rados::blacklist_add(const std::string& client_address,
1023 				 uint32_t expire_seconds) {
1024 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1025 	  return impl->blacklist_add(client_address, expire_seconds);
1026 	}
1027 	
1028 	config_t Rados::cct() {
1029 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1030 	  return reinterpret_cast<config_t>(impl->cct());
1031 	}
1032 	
1033 	int Rados::cluster_fsid(std::string* fsid) {
1034 	  *fsid = "00000000-1111-2222-3333-444444444444";
1035 	  return 0;
1036 	}
1037 	
1038 	int Rados::conf_set(const char *option, const char *value) {
1039 	  return rados_conf_set(reinterpret_cast<rados_t>(client), option, value);
1040 	}
1041 	
1042 	int Rados::conf_get(const char *option, std::string &val) {
1043 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1044 	  CephContext *cct = impl->cct();
1045 	
1046 	  char *str = NULL;
1047 	  int ret = cct->_conf.get_val(option, &str, -1);
1048 	  if (ret != 0) {
1049 	    free(str);
1050 	    return ret;
1051 	  }
1052 	
1053 	  val = str;
1054 	  free(str);
1055 	  return 0;
1056 	}
1057 	
1058 	int Rados::conf_parse_env(const char *env) const {
1059 	  return rados_conf_parse_env(reinterpret_cast<rados_t>(client), env);
1060 	}
1061 	
1062 	int Rados::conf_read_file(const char * const path) const {
1063 	  return rados_conf_read_file(reinterpret_cast<rados_t>(client), path);
1064 	}
1065 	
1066 	int Rados::connect() {
1067 	  return rados_connect(reinterpret_cast<rados_t>(client));
1068 	}
1069 	
1070 	uint64_t Rados::get_instance_id() {
1071 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1072 	  return impl->get_instance_id();
1073 	}
1074 	
1075 	int Rados::get_min_compatible_osd(int8_t* require_osd_release) {
1076 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1077 	  return impl->get_min_compatible_osd(require_osd_release);
1078 	}
1079 	
1080 	int Rados::get_min_compatible_client(int8_t* min_compat_client,
1081 	                                     int8_t* require_min_compat_client) {
1082 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1083 	  return impl->get_min_compatible_client(min_compat_client,
1084 	                                         require_min_compat_client);
1085 	}
1086 	
1087 	int Rados::init(const char * const id) {
1088 	  return rados_create(reinterpret_cast<rados_t *>(&client), id);
1089 	}
1090 	
1091 	int Rados::init_with_context(config_t cct_) {
1092 	  return rados_create_with_context(reinterpret_cast<rados_t *>(&client), cct_);
1093 	}
1094 	
1095 	int Rados::ioctx_create(const char *name, IoCtx &io) {
1096 	  rados_ioctx_t p;
1097 	  int ret = rados_ioctx_create(reinterpret_cast<rados_t>(client), name, &p);
1098 	  if (ret) {
1099 	    return ret;
1100 	  }
1101 	
1102 	  io.close();
1103 	  io.io_ctx_impl = reinterpret_cast<IoCtxImpl*>(p);
1104 	  return 0;
1105 	}
1106 	
1107 	int Rados::ioctx_create2(int64_t pool_id, IoCtx &io)
1108 	{
1109 	  rados_ioctx_t p;
1110 	  int ret = rados_ioctx_create2(reinterpret_cast<rados_t>(client), pool_id, &p);
1111 	  if (ret) {
1112 	    return ret;
1113 	  }
1114 	
1115 	  io.close();
1116 	  io.io_ctx_impl = reinterpret_cast<IoCtxImpl*>(p);
1117 	  return 0;
1118 	}
1119 	
1120 	int Rados::mon_command(std::string cmd, const bufferlist& inbl,
1121 	                       bufferlist *outbl, std::string *outs) {
1122 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1123 	
1124 	  std::vector<std::string> cmds;
1125 	  cmds.push_back(cmd);
1126 	  return impl->mon_command(cmds, inbl, outbl, outs);
1127 	}
1128 	
1129 	int Rados::service_daemon_register(const std::string& service,
1130 	                                   const std::string& name,
1131 	                                   const std::map<std::string,std::string>& metadata) {
1132 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1133 	  return impl->service_daemon_register(service, name, metadata);
1134 	}
1135 	
1136 	int Rados::service_daemon_update_status(std::map<std::string,std::string>&& status) {
1137 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1138 	  return impl->service_daemon_update_status(std::move(status));
1139 	}
1140 	
1141 	int Rados::pool_create(const char *name) {
1142 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1143 	  return impl->pool_create(name);
1144 	}
1145 	
1146 	int Rados::pool_delete(const char *name) {
1147 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1148 	  return impl->pool_delete(name);
1149 	}
1150 	
1151 	int Rados::pool_get_base_tier(int64_t pool, int64_t* base_tier) {
1152 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1153 	  return impl->pool_get_base_tier(pool, base_tier);
1154 	}
1155 	
1156 	int Rados::pool_list(std::list<std::string>& v) {
1157 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1158 	  std::list<std::pair<int64_t, std::string> > pools;
1159 	  int r = impl->pool_list(pools);
1160 	  if (r < 0) {
1161 	    return r;
1162 	  }
1163 	
1164 	  v.clear();
1165 	  for (std::list<std::pair<int64_t, std::string> >::iterator it = pools.begin();
1166 	       it != pools.end(); ++it) {
1167 	    v.push_back(it->second);
1168 	  }
1169 	  return 0;
1170 	}
1171 	
1172 	int Rados::pool_list2(std::list<std::pair<int64_t, std::string> >& v)
1173 	{
1174 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1175 	  return impl->pool_list(v);
1176 	}
1177 	
1178 	int64_t Rados::pool_lookup(const char *name) {
1179 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1180 	  return impl->pool_lookup(name);
1181 	}
1182 	
1183 	int Rados::pool_reverse_lookup(int64_t id, std::string *name) {
1184 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1185 	  return impl->pool_reverse_lookup(id, name);
1186 	}
1187 	
1188 	void Rados::shutdown() {
1189 	  if (client == NULL) {
1190 	    return;
1191 	  }
1192 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1193 	  impl->put();
1194 	  client = NULL;
1195 	}
1196 	
1197 	void Rados::test_blacklist_self(bool set) {
1198 	}
1199 	
1200 	int Rados::wait_for_latest_osdmap() {
1201 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1202 	  return impl->wait_for_latest_osdmap();
1203 	}
1204 	
1205 	int Rados::watch_flush() {
1206 	  TestRadosClient *impl = reinterpret_cast<TestRadosClient*>(client);
1207 	  return impl->watch_flush();
1208 	}
1209 	
1210 	WatchCtx::~WatchCtx() {
1211 	}
1212 	
1213 	WatchCtx2::~WatchCtx2() {
1214 	}
1215 	
1216 	} // namespace librados
1217 	
1218 	int cls_cxx_create(cls_method_context_t hctx, bool exclusive) {
1219 	  librados::TestClassHandler::MethodContext *ctx =
1220 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1221 	  return ctx->io_ctx_impl->create(ctx->oid, exclusive, ctx->snapc);
1222 	}
1223 	
1224 	int cls_cxx_remove(cls_method_context_t hctx) {
1225 	  librados::TestClassHandler::MethodContext *ctx =
1226 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1227 	  return ctx->io_ctx_impl->remove(ctx->oid, ctx->io_ctx_impl->get_snap_context());
1228 	}
1229 	
1230 	int cls_get_request_origin(cls_method_context_t hctx, entity_inst_t *origin) {
1231 	  librados::TestClassHandler::MethodContext *ctx =
1232 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1233 	
1234 	  librados::TestRadosClient *rados_client =
1235 	    ctx->io_ctx_impl->get_rados_client();
1236 	
1237 	  struct sockaddr_in sin;
1238 	  memset(&sin, 0, sizeof(sin));
1239 	  sin.sin_family = AF_INET;
1240 	  sin.sin_port = 0;
1241 	  inet_pton(AF_INET, "127.0.0.1", &sin.sin_addr);
1242 	
1243 	  entity_addr_t entity_addr(entity_addr_t::TYPE_DEFAULT,
1244 	                            rados_client->get_nonce());
1245 	  entity_addr.in4_addr() = sin;
1246 	
1247 	  *origin = entity_inst_t(
1248 	    entity_name_t::CLIENT(rados_client->get_instance_id()),
1249 	    entity_addr);
1250 	  return 0;
1251 	}
1252 	
1253 	int cls_cxx_getxattr(cls_method_context_t hctx, const char *name,
1254 	                     bufferlist *outbl) {
1255 	  std::map<string, bufferlist> attrs;
1256 	  int r = cls_cxx_getxattrs(hctx, &attrs);
1257 	  if (r < 0) {
1258 	    return r;
1259 	  }
1260 	
1261 	  std::map<string, bufferlist>::iterator it = attrs.find(name);
1262 	  if (it == attrs.end()) {
1263 	    return -ENODATA;
1264 	  }
1265 	  *outbl = it->second;
1266 	  return 0;
1267 	}
1268 	
1269 	int cls_cxx_getxattrs(cls_method_context_t hctx, std::map<string, bufferlist> *attrset) {
1270 	  librados::TestClassHandler::MethodContext *ctx =
1271 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1272 	  return ctx->io_ctx_impl->xattr_get(ctx->oid, attrset);
1273 	}
1274 	
1275 	int cls_cxx_map_get_keys(cls_method_context_t hctx, const string &start_obj,
1276 	                         uint64_t max_to_get, std::set<string> *keys, bool *more) {
1277 	  librados::TestClassHandler::MethodContext *ctx =
1278 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1279 	
1280 	  keys->clear();
1281 	  std::map<string, bufferlist> vals;
1282 	  int r = ctx->io_ctx_impl->omap_get_vals2(ctx->oid, start_obj, "", max_to_get,
1283 	                                           &vals, more);
1284 	  if (r < 0) {
1285 	    return r;
1286 	  }
1287 	
1288 	  for (std::map<string, bufferlist>::iterator it = vals.begin();
1289 	       it != vals.end(); ++it) {
1290 	    keys->insert(it->first);
1291 	  }
1292 	  return keys->size();
1293 	}
1294 	
1295 	int cls_cxx_map_get_val(cls_method_context_t hctx, const string &key,
1296 	                        bufferlist *outbl) {
1297 	  librados::TestClassHandler::MethodContext *ctx =
1298 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1299 	
1300 	  std::map<string, bufferlist> vals;
1301 	  int r = ctx->io_ctx_impl->omap_get_vals(ctx->oid, "", key, 1024, &vals);
1302 	  if (r < 0) {
1303 	    return r;
1304 	  }
1305 	
1306 	  std::map<string, bufferlist>::iterator it = vals.find(key);
1307 	  if (it == vals.end()) {
1308 	    return -ENOENT;
1309 	  }
1310 	
1311 	  *outbl = it->second;
1312 	  return 0;
1313 	}
1314 	
1315 	int cls_cxx_map_get_vals(cls_method_context_t hctx, const string &start_obj,
1316 	                         const string &filter_prefix, uint64_t max_to_get,
1317 	                         std::map<string, bufferlist> *vals, bool *more) {
1318 	  librados::TestClassHandler::MethodContext *ctx =
1319 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1320 	  int r = ctx->io_ctx_impl->omap_get_vals2(ctx->oid, start_obj, filter_prefix,
1321 						  max_to_get, vals, more);
1322 	  if (r < 0) {
1323 	    return r;
1324 	  }
1325 	  return vals->size();
1326 	}
1327 	
1328 	int cls_cxx_map_remove_key(cls_method_context_t hctx, const string &key) {
1329 	  std::set<std::string> keys;
1330 	  keys.insert(key);
1331 	
1332 	  librados::TestClassHandler::MethodContext *ctx =
1333 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1334 	  return ctx->io_ctx_impl->omap_rm_keys(ctx->oid, keys);
1335 	}
1336 	
1337 	int cls_cxx_map_set_val(cls_method_context_t hctx, const string &key,
1338 	                        bufferlist *inbl) {
1339 	  std::map<std::string, bufferlist> m;
1340 	  m[key] = *inbl;
1341 	  return cls_cxx_map_set_vals(hctx, &m);
1342 	}
1343 	
1344 	int cls_cxx_map_set_vals(cls_method_context_t hctx,
1345 	                         const std::map<string, bufferlist> *map) {
1346 	  librados::TestClassHandler::MethodContext *ctx =
1347 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1348 	  return ctx->io_ctx_impl->omap_set(ctx->oid, *map);
1349 	}
1350 	
1351 	int cls_cxx_read(cls_method_context_t hctx, int ofs, int len,
1352 	                 bufferlist *outbl) {
1353 	  return cls_cxx_read2(hctx, ofs, len, outbl, 0);
1354 	}
1355 	
1356 	int cls_cxx_read2(cls_method_context_t hctx, int ofs, int len,
1357 	                  bufferlist *outbl, uint32_t op_flags) {
1358 	  librados::TestClassHandler::MethodContext *ctx =
1359 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1360 	  return ctx->io_ctx_impl->read(ctx->oid, len, ofs, outbl);
1361 	}
1362 	
1363 	int cls_cxx_setxattr(cls_method_context_t hctx, const char *name,
1364 	                     bufferlist *inbl) {
1365 	  librados::TestClassHandler::MethodContext *ctx =
1366 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1367 	  return ctx->io_ctx_impl->xattr_set(ctx->oid, name, *inbl);
1368 	}
1369 	
1370 	int cls_cxx_stat(cls_method_context_t hctx, uint64_t *size, time_t *mtime) {
1371 	  librados::TestClassHandler::MethodContext *ctx =
1372 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1373 	  return ctx->io_ctx_impl->stat(ctx->oid, size, mtime);
1374 	}
1375 	
1376 	int cls_cxx_write(cls_method_context_t hctx, int ofs, int len,
1377 	                  bufferlist *inbl) {
1378 	  return cls_cxx_write2(hctx, ofs, len, inbl, 0);
1379 	}
1380 	
1381 	int cls_cxx_write2(cls_method_context_t hctx, int ofs, int len,
1382 	                   bufferlist *inbl, uint32_t op_flags) {
1383 	  librados::TestClassHandler::MethodContext *ctx =
1384 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1385 	  return ctx->io_ctx_impl->write(ctx->oid, *inbl, len, ofs, ctx->snapc);
1386 	}
1387 	
1388 	int cls_cxx_write_full(cls_method_context_t hctx, bufferlist *inbl) {
1389 	  librados::TestClassHandler::MethodContext *ctx =
1390 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1391 	  return ctx->io_ctx_impl->write_full(ctx->oid, *inbl, ctx->snapc);
1392 	}
1393 	
1394 	int cls_cxx_replace(cls_method_context_t hctx, int ofs, int len,
1395 	                    bufferlist *inbl) {
1396 	  librados::TestClassHandler::MethodContext *ctx =
1397 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1398 	  int r = ctx->io_ctx_impl->truncate(ctx->oid, 0, ctx->snapc);
1399 	  if (r < 0) {
1400 	    return r;
1401 	  }
1402 	  return ctx->io_ctx_impl->write(ctx->oid, *inbl, len, ofs, ctx->snapc);
1403 	}
1404 	
1405 	int cls_cxx_truncate(cls_method_context_t hctx, int ofs) {
1406 	  librados::TestClassHandler::MethodContext *ctx =
1407 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1408 	  return ctx->io_ctx_impl->truncate(ctx->oid, ofs, ctx->snapc);
1409 	}
1410 	
1411 	int cls_cxx_list_watchers(cls_method_context_t hctx,
1412 				  obj_list_watch_response_t *watchers) {
1413 	  librados::TestClassHandler::MethodContext *ctx =
1414 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1415 	
1416 	  std::list<obj_watch_t> obj_watchers;
1417 	  int r = ctx->io_ctx_impl->list_watchers(ctx->oid, &obj_watchers);
(1) Event cond_false: Condition "r < 0", taking false branch.
1418 	  if (r < 0) {
1419 	    return r;
(2) Event if_end: End of if statement.
1420 	  }
1421 	
(3) Event for_loop: Iterating over another element of "obj_watchers".
1422 	  for (auto &w : obj_watchers) {
1423 	    watch_item_t watcher;
1424 	    watcher.name = entity_name_t::CLIENT(w.watcher_id);
1425 	    watcher.cookie = w.cookie;
1426 	    watcher.timeout_seconds = w.timeout_seconds;
(4) Event check_return: Calling "parse" without checking return value (as is done elsewhere 9 out of 10 times).
Also see events: [example_checked][example_checked][example_checked][example_checked][example_assign][example_checked]
1427 	    watcher.addr.parse(w.addr, 0);
1428 	    watchers->entries.push_back(watcher);
1429 	  }
1430 	
1431 	  return 0;
1432 	}
1433 	
1434 	uint64_t cls_get_features(cls_method_context_t hctx) {
1435 	  return CEPH_FEATURES_SUPPORTED_DEFAULT;
1436 	}
1437 	
1438 	uint64_t cls_get_client_features(cls_method_context_t hctx) {
1439 	  return CEPH_FEATURES_SUPPORTED_DEFAULT;
1440 	}
1441 	
1442 	int cls_get_snapset_seq(cls_method_context_t hctx, uint64_t *snap_seq) {
1443 	  librados::TestClassHandler::MethodContext *ctx =
1444 	    reinterpret_cast<librados::TestClassHandler::MethodContext*>(hctx);
1445 	  librados::snap_set_t snapset;
1446 	  int r = ctx->io_ctx_impl->list_snaps(ctx->oid, &snapset);
1447 	  if (r < 0) {
1448 	    return r;
1449 	  }
1450 	
1451 	  *snap_seq = snapset.seq;
1452 	  return 0;
1453 	}
1454 	
1455 	int cls_log(int level, const char *format, ...) {
1456 	  int size = 256;
1457 	  va_list ap;
1458 	  while (1) {
1459 	    char buf[size];
1460 	    va_start(ap, format);
1461 	    int n = vsnprintf(buf, size, format, ap);
1462 	    va_end(ap);
1463 	    if ((n > -1 && n < size) || size > 8196) {
1464 	      dout(ceph::dout::need_dynamic(level)) << buf << dendl;
1465 	      return n;
1466 	    }
1467 	    size *= 2;
1468 	  }
1469 	  return 0;
1470 	}
1471 	
1472 	int cls_register(const char *name, cls_handle_t *handle) {
1473 	  librados::TestClassHandler *cls = get_class_handler();
1474 	  return cls->create(name, handle);
1475 	}
1476 	
1477 	int cls_register_cxx_method(cls_handle_t hclass, const char *method,
1478 	    int flags,
1479 	    cls_method_cxx_call_t class_call,
1480 	    cls_method_handle_t *handle) {
1481 	  librados::TestClassHandler *cls = get_class_handler();
1482 	  return cls->create_method(hclass, method, class_call, handle);
1483 	}
1484 	
1485 	int cls_register_cxx_filter(cls_handle_t hclass,
1486 	                            const std::string &filter_name,
1487 	                            cls_cxx_filter_factory_t fn,
1488 	                            cls_filter_handle_t *)
1489 	{
1490 	  librados::TestClassHandler *cls = get_class_handler();
1491 	  return cls->create_filter(hclass, filter_name, fn);
1492 	}
1493 	
1494 	ceph_release_t cls_get_required_osd_release(cls_handle_t hclass) {
1495 	  return ceph_release_t::nautilus;
1496 	}
1497 	
1498 	ceph_release_t cls_get_min_compatible_client(cls_handle_t hclass) {
1499 	  return ceph_release_t::nautilus;
1500 	}
1501 	
1502 	// stubs to silence TestClassHandler::open_class()
1503 	PGLSFilter::~PGLSFilter()
1504 	{}
1505 	
1506 	int cls_gen_rand_base64(char *, int) {
1507 	  return -ENOTSUP;
1508 	}
1509 	
1510 	int cls_cxx_chunk_write_and_set(cls_method_handle_t, int,
1511 					int, bufferlist *,
1512 					uint32_t, bufferlist *, int) {
1513 	  return -ENOTSUP;
1514 	}
1515 	
1516 	int cls_cxx_map_read_header(cls_method_handle_t, bufferlist *) {
1517 	  return -ENOTSUP;
1518 	}
1519 	
1520 	uint64_t cls_get_osd_min_alloc_size(cls_method_context_t hctx) {
1521 	  return 0;
1522 	}
1523