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) 2011 New Dream Network
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   	#include "include/int_types.h"
15   	
16   	#include <errno.h>
17   	
18   	#include "common/deleter.h"
19   	#include "common/dout.h"
20   	#include "common/errno.h"
21   	#include "common/TracepointProvider.h"
22   	#include "include/Context.h"
23   	
24   	#include "cls/rbd/cls_rbd_client.h"
25   	#include "cls/rbd/cls_rbd_types.h"
26   	#include "librbd/ImageCtx.h"
27   	#include "librbd/ImageState.h"
28   	#include "librbd/internal.h"
29   	#include "librbd/Operations.h"
30   	#include "librbd/api/Config.h"
31   	#include "librbd/api/DiffIterate.h"
32   	#include "librbd/api/Group.h"
33   	#include "librbd/api/Image.h"
34   	#include "librbd/api/Migration.h"
35   	#include "librbd/api/Mirror.h"
36   	#include "librbd/api/Namespace.h"
37   	#include "librbd/api/Pool.h"
38   	#include "librbd/api/PoolMetadata.h"
39   	#include "librbd/api/Snapshot.h"
40   	#include "librbd/api/Trash.h"
41   	#include "librbd/io/AioCompletion.h"
42   	#include "librbd/io/ImageRequestWQ.h"
43   	#include "librbd/io/ReadResult.h"
44   	#include <algorithm>
45   	#include <string>
46   	#include <vector>
47   	
48   	#ifdef WITH_LTTNG
49   	#define TRACEPOINT_DEFINE
50   	#define TRACEPOINT_PROBE_DYNAMIC_LINKAGE
51   	#include "tracing/librbd.h"
52   	#undef TRACEPOINT_PROBE_DYNAMIC_LINKAGE
53   	#undef TRACEPOINT_DEFINE
54   	#else
55   	#define tracepoint(...)
56   	#endif
57   	
58   	#define dout_subsys ceph_subsys_rbd
59   	#undef dout_prefix
60   	#define dout_prefix *_dout << "librbd: "
61   	
62   	using std::string;
63   	using std::vector;
64   	
65   	using ceph::bufferlist;
66   	using librados::snap_t;
67   	using librados::IoCtx;
68   	
69   	namespace {
70   	
71   	TracepointProvider::Traits tracepoint_traits("librbd_tp.so", "rbd_tracing");
72   	
73   	struct UserBufferDeleter : public deleter::impl {
74   	  CephContext* cct;
75   	  librbd::io::AioCompletion* aio_completion;
76   	
77   	  UserBufferDeleter(CephContext* cct, librbd::io::AioCompletion* aio_completion)
78   	    : deleter::impl(deleter()), cct(cct), aio_completion(aio_completion) {
79   	   aio_completion->block(cct);
80   	  }
81   	
82   	  ~UserBufferDeleter() override {
83   	    aio_completion->unblock(cct);
84   	  }
85   	};
86   	
87   	static auto create_write_raw(librbd::ImageCtx *ictx, const char *buf,
88   	                             size_t len,
89   	                             librbd::io::AioCompletion* aio_completion) {
90   	  if (ictx->disable_zero_copy || aio_completion == nullptr) {
91   	    // must copy the buffer if writeback/writearound cache is in-use (or using
92   	    // non-AIO)
93   	    return buffer::copy(buf, len);
94   	  }
95   	
96   	  // avoid copying memory for AIO operations, but possibly delay completions
97   	  // until the last reference to the user's memory has been released
98   	  return ceph::unique_leakable_ptr<ceph::buffer::raw>(
99   	    buffer::claim_buffer(
100  	      len, const_cast<char*>(buf),
101  	      deleter(new UserBufferDeleter(ictx->cct, aio_completion))));
102  	}
103  	
104  	CephContext* get_cct(IoCtx &io_ctx) {
105  	  return reinterpret_cast<CephContext*>(io_ctx.cct());
106  	}
107  	
108  	librbd::io::AioCompletion* get_aio_completion(librbd::RBD::AioCompletion *comp) {
109  	  return reinterpret_cast<librbd::io::AioCompletion *>(comp->pc);
110  	}
111  	
112  	struct C_AioCompletion : public Context {
113  	  CephContext *cct;
114  	  librbd::io::aio_type_t aio_type;
115  	  librbd::io::AioCompletion* aio_comp;
116  	
117  	  C_AioCompletion(librbd::ImageCtx *ictx, librbd::io::aio_type_t aio_type,
118  	                  librbd::io::AioCompletion* aio_comp)
119  	    : cct(ictx->cct), aio_type(aio_type), aio_comp(aio_comp) {
120  	    aio_comp->init_time(ictx, aio_type);
121  	    aio_comp->get();
122  	  }
123  	  virtual ~C_AioCompletion() {
124  	    aio_comp->put();
125  	  }
126  	
127  	  void finish(int r) override {
128  	    ldout(cct, 20) << "C_AioComplete::finish: r=" << r << dendl;
129  	    if (r < 0) {
130  	      aio_comp->fail(r);
131  	    } else {
132  	      aio_comp->complete();
133  	    }
134  	  }
135  	};
136  	
137  	struct C_OpenComplete : public C_AioCompletion {
138  	  librbd::ImageCtx *ictx;
139  	  void **ictxp;
140  	  C_OpenComplete(librbd::ImageCtx *ictx, librbd::io::AioCompletion* comp,
141  			 void **ictxp)
142  	    : C_AioCompletion(ictx, librbd::io::AIO_TYPE_OPEN, comp),
143  	      ictx(ictx), ictxp(ictxp) {
144  	  }
145  	  void finish(int r) override {
146  	    ldout(ictx->cct, 20) << "C_OpenComplete::finish: r=" << r << dendl;
147  	    if (r < 0) {
148  	      *ictxp = nullptr;
149  	    } else {
150  	      *ictxp = ictx;
151  	    }
152  	
153  	    C_AioCompletion::finish(r);
154  	  }
155  	};
156  	
157  	struct C_OpenAfterCloseComplete : public Context {
158  	  librbd::ImageCtx *ictx;
159  	  librbd::io::AioCompletion* comp;
160  	  void **ictxp;
161  	  C_OpenAfterCloseComplete(librbd::ImageCtx *ictx,
162  	                           librbd::io::AioCompletion* comp,
163  				   void **ictxp)
164  	    : ictx(ictx), comp(comp), ictxp(ictxp) {
165  	  }
166  	  void finish(int r) override {
167  	    ldout(ictx->cct, 20) << "C_OpenAfterCloseComplete::finish: r=" << r
168  				 << dendl;
169  	    delete reinterpret_cast<librbd::ImageCtx*>(*ictxp);
170  	    *ictxp = nullptr;
171  	
172  	    ictx->state->open(0, new C_OpenComplete(ictx, comp, ictxp));
173  	  }
174  	};
175  	
176  	struct C_UpdateWatchCB : public librbd::UpdateWatchCtx {
177  	  rbd_update_callback_t watch_cb;
178  	  void *arg;
179  	  uint64_t handle = 0;
180  	
181  	  C_UpdateWatchCB(rbd_update_callback_t watch_cb, void *arg) :
182  	    watch_cb(watch_cb), arg(arg) {
183  	  }
184  	  void handle_notify() override {
185  	    watch_cb(arg);
186  	  }
187  	};
188  	
189  	void group_image_status_cpp_to_c(const librbd::group_image_info_t &cpp_info,
190  					 rbd_group_image_info_t *c_info) {
191  	  c_info->name = strdup(cpp_info.name.c_str());
192  	  c_info->pool = cpp_info.pool;
193  	  c_info->state = cpp_info.state;
194  	}
195  	
196  	void group_info_cpp_to_c(const librbd::group_info_t &cpp_info,
197  				 rbd_group_info_t *c_info) {
198  	  c_info->name = strdup(cpp_info.name.c_str());
199  	  c_info->pool = cpp_info.pool;
200  	}
201  	
202  	void group_snap_info_cpp_to_c(const librbd::group_snap_info_t &cpp_info,
203  				      rbd_group_snap_info_t *c_info) {
204  	  c_info->name = strdup(cpp_info.name.c_str());
205  	  c_info->state = cpp_info.state;
206  	}
207  	
208  	void mirror_image_info_cpp_to_c(const librbd::mirror_image_info_t &cpp_info,
209  					rbd_mirror_image_info_t *c_info) {
210  	  c_info->global_id = strdup(cpp_info.global_id.c_str());
211  	  c_info->state = cpp_info.state;
212  	  c_info->primary = cpp_info.primary;
213  	}
214  	
215  	void mirror_image_status_cpp_to_c(const librbd::mirror_image_status_t &cpp_status,
216  					  rbd_mirror_image_status_t *c_status) {
217  	  c_status->name = strdup(cpp_status.name.c_str());
218  	  mirror_image_info_cpp_to_c(cpp_status.info, &c_status->info);
219  	  c_status->state = cpp_status.state;
220  	  c_status->description = strdup(cpp_status.description.c_str());
221  	  c_status->last_update = cpp_status.last_update;
222  	  c_status->up = cpp_status.up;
223  	}
224  	
225  	void trash_image_info_cpp_to_c(const librbd::trash_image_info_t &cpp_info,
226  	                               rbd_trash_image_info_t *c_info) {
227  	  c_info->id = strdup(cpp_info.id.c_str());
228  	  c_info->name = strdup(cpp_info.name.c_str());
229  	  c_info->source = cpp_info.source;
230  	  c_info->deletion_time = cpp_info.deletion_time;
231  	  c_info->deferment_end_time = cpp_info.deferment_end_time;
232  	}
233  	
234  	void config_option_cpp_to_c(const librbd::config_option_t &cpp_option,
235  	                            rbd_config_option_t *c_option) {
236  	  c_option->name = strdup(cpp_option.name.c_str());
237  	  c_option->value = strdup(cpp_option.value.c_str());
238  	  c_option->source = cpp_option.source;
239  	}
240  	
241  	void config_option_cleanup(rbd_config_option_t &option) {
242  	    free(option.name);
243  	    free(option.value);
244  	}
245  	
246  	struct C_MirrorImageGetInfo : public Context {
247  	    rbd_mirror_image_info_t *mirror_image_info;
248  	  Context *on_finish;
249  	
250  	  librbd::mirror_image_info_t cpp_mirror_image_info;
251  	
252  	  C_MirrorImageGetInfo(rbd_mirror_image_info_t *mirror_image_info,
253  	                         Context *on_finish)
254  	    : mirror_image_info(mirror_image_info), on_finish(on_finish) {
255  	  }
256  	
257  	  void finish(int r) override {
258  	    if (r < 0) {
259  	      on_finish->complete(r);
260  	      return;
261  	    }
262  	
263  	    mirror_image_info_cpp_to_c(cpp_mirror_image_info, mirror_image_info);
264  	    on_finish->complete(0);
265  	  }
266  	};
267  	
268  	struct C_MirrorImageGetStatus : public Context {
269  	  rbd_mirror_image_status_t *mirror_image_status;
270  	  Context *on_finish;
271  	
272  	  librbd::mirror_image_status_t cpp_mirror_image_status;
273  	
274  	  C_MirrorImageGetStatus(rbd_mirror_image_status_t *mirror_image_status,
275  	                         Context *on_finish)
276  	    : mirror_image_status(mirror_image_status), on_finish(on_finish) {
277  	  }
278  	
279  	  void finish(int r) override {
280  	    if (r < 0) {
281  	      on_finish->complete(r);
282  	      return;
283  	    }
284  	
285  	    mirror_image_status_cpp_to_c(cpp_mirror_image_status, mirror_image_status);
286  	    on_finish->complete(0);
287  	  }
288  	};
289  	
290  	} // anonymous namespace
291  	
292  	namespace librbd {
293  	  ProgressContext::~ProgressContext()
294  	  {
295  	  }
296  	
297  	  class CProgressContext : public ProgressContext
298  	  {
299  	  public:
300  	    CProgressContext(librbd_progress_fn_t fn, void *data)
301  	      : m_fn(fn), m_data(data)
302  	    {
303  	    }
304  	    int update_progress(uint64_t offset, uint64_t src_size) override
305  	    {
306  	      return m_fn(offset, src_size, m_data);
307  	    }
308  	  private:
309  	    librbd_progress_fn_t m_fn;
310  	    void *m_data;
311  	  };
312  	
313  	  /*
314  	   * Pool stats
315  	   */
316  	  PoolStats::PoolStats() {
317  	    rbd_pool_stats_create(&pool_stats);
318  	  }
319  	
320  	  PoolStats::~PoolStats() {
321  	    rbd_pool_stats_destroy(pool_stats);
322  	  }
323  	
324  	  int PoolStats::add(rbd_pool_stat_option_t option, uint64_t* opt_val) {
325  	    return rbd_pool_stats_option_add_uint64(pool_stats, option, opt_val);
326  	  }
327  	
328  	  /*
329  	   *  RBD
330  	   */
331  	  RBD::RBD()
332  	  {
333  	  }
334  	
335  	  RBD::~RBD()
336  	  {
337  	  }
338  	
339  	  void RBD::version(int *major, int *minor, int *extra)
340  	  {
341  	    rbd_version(major, minor, extra);
342  	  }
343  	
344  	  int RBD::open(IoCtx& io_ctx, Image& image, const char *name)
345  	  {
346  	    return open(io_ctx, image, name, NULL);
347  	  }
348  	
349  	  int RBD::open_by_id(IoCtx& io_ctx, Image& image, const char *id)
350  	  {
351  	    return open_by_id(io_ctx, image, id, nullptr);
352  	  }
353  	
354  	  int RBD::open(IoCtx& io_ctx, Image& image, const char *name,
355  			const char *snap_name)
356  	  {
357  	    ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, false);
(14) Event template_instantiation_context: instantiation of "void TracepointProvider::initialize<traits>(CephContext *) [with traits=<unnamed>::tracepoint_traits]" at line 358 of "../../../src/librbd/librbd.cc"
Also see events: [no_matching_constructor][caretline][argument_list_types_add_on][compiler_generated_function_context][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context][context_lines_skipped][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context]
358  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
359  	    tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
360  	
361  	    if (image.ctx != NULL) {
362  	      reinterpret_cast<ImageCtx*>(image.ctx)->state->close();
363  	      image.ctx = NULL;
364  	    }
365  	
366  	    int r = ictx->state->open(0);
367  	    if (r < 0) {
368  	      tracepoint(librbd, open_image_exit, r);
369  	      return r;
370  	    }
371  	
372  	    image.ctx = (image_ctx_t) ictx;
373  	    tracepoint(librbd, open_image_exit, 0);
374  	    return 0;
375  	  }
376  	
377  	  int RBD::open_by_id(IoCtx& io_ctx, Image& image, const char *id,
378  			      const char *snap_name)
379  	  {
380  	    ImageCtx *ictx = new ImageCtx("", id, snap_name, io_ctx, false);
381  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
382  	    tracepoint(librbd, open_image_by_id_enter, ictx, ictx->id.c_str(),
383  	               ictx->snap_name.c_str(), ictx->read_only);
384  	
385  	    if (image.ctx != nullptr) {
386  	      reinterpret_cast<ImageCtx*>(image.ctx)->state->close();
387  	      image.ctx = nullptr;
388  	    }
389  	
390  	    int r = ictx->state->open(0);
391  	    if (r < 0) {
392  	      tracepoint(librbd, open_image_by_id_exit, r);
393  	      return r;
394  	    }
395  	
396  	    image.ctx = (image_ctx_t) ictx;
397  	    tracepoint(librbd, open_image_by_id_exit, 0);
398  	    return 0;
399  	  }
400  	
401  	  int RBD::aio_open(IoCtx& io_ctx, Image& image, const char *name,
402  			    const char *snap_name, RBD::AioCompletion *c)
403  	  {
404  	    ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, false);
405  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
406  	    tracepoint(librbd, aio_open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only, c->pc);
407  	
408  	    if (image.ctx != NULL) {
409  	      reinterpret_cast<ImageCtx*>(image.ctx)->state->close(
410  		new C_OpenAfterCloseComplete(ictx, get_aio_completion(c), &image.ctx));
411  	    } else {
412  	      ictx->state->open(0, new C_OpenComplete(ictx, get_aio_completion(c),
413  	                                              &image.ctx));
414  	    }
415  	    tracepoint(librbd, aio_open_image_exit, 0);
416  	    return 0;
417  	  }
418  	
419  	  int RBD::aio_open_by_id(IoCtx& io_ctx, Image& image, const char *id,
420  			          const char *snap_name, RBD::AioCompletion *c)
421  	  {
422  	    ImageCtx *ictx = new ImageCtx("", id, snap_name, io_ctx, false);
423  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
424  	    tracepoint(librbd, aio_open_image_by_id_enter, ictx, ictx->id.c_str(),
425  	               ictx->snap_name.c_str(), ictx->read_only, c->pc);
426  	
427  	    if (image.ctx != nullptr) {
428  	      reinterpret_cast<ImageCtx*>(image.ctx)->state->close(
429  		new C_OpenAfterCloseComplete(ictx, get_aio_completion(c), &image.ctx));
430  	    } else {
431  	      ictx->state->open(0, new C_OpenComplete(ictx, get_aio_completion(c),
432  	                                              &image.ctx));
433  	    }
434  	    tracepoint(librbd, aio_open_image_by_id_exit, 0);
435  	    return 0;
436  	  }
437  	
438  	  int RBD::open_read_only(IoCtx& io_ctx, Image& image, const char *name,
439  				  const char *snap_name)
440  	  {
441  	    ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, true);
442  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
443  	    tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
444  	
445  	    if (image.ctx != NULL) {
446  	      reinterpret_cast<ImageCtx*>(image.ctx)->state->close();
447  	      image.ctx = NULL;
448  	    }
449  	
450  	    int r = ictx->state->open(0);
451  	    if (r < 0) {
452  	      tracepoint(librbd, open_image_exit, r);
453  	      return r;
454  	    }
455  	
456  	    image.ctx = (image_ctx_t) ictx;
457  	    tracepoint(librbd, open_image_exit, 0);
458  	    return 0;
459  	  }
460  	
461  	  int RBD::open_by_id_read_only(IoCtx& io_ctx, Image& image, const char *id,
462  				        const char *snap_name)
463  	  {
464  	    ImageCtx *ictx = new ImageCtx("", id, snap_name, io_ctx, true);
465  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
466  	    tracepoint(librbd, open_image_by_id_enter, ictx, ictx->id.c_str(),
467  	               ictx->snap_name.c_str(), ictx->read_only);
468  	
469  	    if (image.ctx != nullptr) {
470  	      reinterpret_cast<ImageCtx*>(image.ctx)->state->close();
471  	      image.ctx = nullptr;
472  	    }
473  	
474  	    int r = ictx->state->open(0);
475  	    if (r < 0) {
476  	      tracepoint(librbd, open_image_by_id_exit, r);
477  	      return r;
478  	    }
479  	
480  	    image.ctx = (image_ctx_t) ictx;
481  	    tracepoint(librbd, open_image_by_id_exit, 0);
482  	    return 0;
483  	  }
484  	
485  	  int RBD::aio_open_read_only(IoCtx& io_ctx, Image& image, const char *name,
486  				      const char *snap_name, RBD::AioCompletion *c)
487  	  {
488  	    ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, true);
489  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
490  	    tracepoint(librbd, aio_open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only, c->pc);
491  	
492  	    if (image.ctx != NULL) {
493  	      reinterpret_cast<ImageCtx*>(image.ctx)->state->close(
494  		new C_OpenAfterCloseComplete(ictx, get_aio_completion(c), &image.ctx));
495  	    } else {
496  	      ictx->state->open(0, new C_OpenComplete(ictx, get_aio_completion(c),
497  	                                              &image.ctx));
498  	    }
499  	    tracepoint(librbd, aio_open_image_exit, 0);
500  	    return 0;
501  	  }
502  	
503  	  int RBD::aio_open_by_id_read_only(IoCtx& io_ctx, Image& image, const char *id,
504  		                            const char *snap_name, RBD::AioCompletion *c)
505  	  {
506  	    ImageCtx *ictx = new ImageCtx("", id, snap_name, io_ctx, true);
507  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
508  	    tracepoint(librbd, aio_open_image_by_id_enter, ictx, ictx->id.c_str(),
509  	               ictx->snap_name.c_str(), ictx->read_only, c->pc);
510  	
511  	    if (image.ctx != nullptr) {
512  	      reinterpret_cast<ImageCtx*>(image.ctx)->state->close(
513  		new C_OpenAfterCloseComplete(ictx, get_aio_completion(c), &image.ctx));
514  	    } else {
515  	      ictx->state->open(0, new C_OpenComplete(ictx, get_aio_completion(c),
516  	                                              &image.ctx));
517  	    }
518  	    tracepoint(librbd, aio_open_image_by_id_exit, 0);
519  	    return 0;
520  	  }
521  	
522  	  int RBD::create(IoCtx& io_ctx, const char *name, uint64_t size, int *order)
523  	  {
524  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
525  	    tracepoint(librbd, create_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, *order);
526  	    int r = librbd::create(io_ctx, name, size, order);
527  	    tracepoint(librbd, create_exit, r, *order);
528  	    return r;
529  	  }
530  	
531  	  int RBD::create2(IoCtx& io_ctx, const char *name, uint64_t size,
532  			   uint64_t features, int *order)
533  	  {
534  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
535  	    tracepoint(librbd, create2_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, features, *order);
536  	    int r = librbd::create(io_ctx, name, size, false, features, order, 0, 0);
537  	    tracepoint(librbd, create2_exit, r, *order);
538  	    return r;
539  	  }
540  	
541  	  int RBD::create3(IoCtx& io_ctx, const char *name, uint64_t size,
542  			   uint64_t features, int *order, uint64_t stripe_unit,
543  			   uint64_t stripe_count)
544  	  {
545  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
546  	    tracepoint(librbd, create3_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, features, *order, stripe_unit, stripe_count);
547  	    int r = librbd::create(io_ctx, name, size, false, features, order,
548  				  stripe_unit, stripe_count);
549  	    tracepoint(librbd, create3_exit, r, *order);
550  	    return r;
551  	  }
552  	
553  	  int RBD::create4(IoCtx& io_ctx, const char *name, uint64_t size,
554  			   ImageOptions& opts)
555  	  {
556  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
557  	    tracepoint(librbd, create4_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, opts.opts);
558  	    int r = librbd::create(io_ctx, name, "", size, opts, "", "", false);
559  	    tracepoint(librbd, create4_exit, r);
560  	    return r;
561  	  }
562  	
563  	  int RBD::clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
564  			 IoCtx& c_ioctx, const char *c_name, uint64_t features,
565  			 int *c_order)
566  	  {
567  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioctx));
568  	    tracepoint(librbd, clone_enter, p_ioctx.get_pool_name().c_str(), p_ioctx.get_id(), p_name, p_snap_name, c_ioctx.get_pool_name().c_str(), c_ioctx.get_id(), c_name, features);
569  	    int r = librbd::clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name,
570  				 features, c_order, 0, 0);
571  	    tracepoint(librbd, clone_exit, r, *c_order);
572  	    return r;
573  	  }
574  	
575  	  int RBD::clone2(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
576  			  IoCtx& c_ioctx, const char *c_name, uint64_t features,
577  			  int *c_order, uint64_t stripe_unit, int stripe_count)
578  	  {
579  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioctx));
580  	    tracepoint(librbd, clone2_enter, p_ioctx.get_pool_name().c_str(), p_ioctx.get_id(), p_name, p_snap_name, c_ioctx.get_pool_name().c_str(), c_ioctx.get_id(), c_name, features, stripe_unit, stripe_count);
581  	    int r = librbd::clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name,
582  				 features, c_order, stripe_unit, stripe_count);
583  	    tracepoint(librbd, clone2_exit, r, *c_order);
584  	    return r;
585  	  }
586  	
587  	  int RBD::clone3(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
588  			  IoCtx& c_ioctx, const char *c_name, ImageOptions& c_opts)
589  	  {
590  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioctx));
591  	    tracepoint(librbd, clone3_enter, p_ioctx.get_pool_name().c_str(), p_ioctx.get_id(), p_name, p_snap_name, c_ioctx.get_pool_name().c_str(), c_ioctx.get_id(), c_name, c_opts.opts);
592  	    int r = librbd::clone(p_ioctx, nullptr, p_name, p_snap_name, c_ioctx,
593  	                          nullptr, c_name, c_opts, "", "");
594  	    tracepoint(librbd, clone3_exit, r);
595  	    return r;
596  	  }
597  	
598  	  int RBD::remove(IoCtx& io_ctx, const char *name)
599  	  {
600  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
601  	    tracepoint(librbd, remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name);
602  	    librbd::NoOpProgressContext prog_ctx;
603  	    int r = librbd::api::Image<>::remove(io_ctx, name, prog_ctx);
604  	    tracepoint(librbd, remove_exit, r);
605  	    return r;
606  	  }
607  	
608  	  int RBD::remove_with_progress(IoCtx& io_ctx, const char *name,
609  					ProgressContext& pctx)
610  	  {
611  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
612  	    tracepoint(librbd, remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name);
613  	    int r = librbd::api::Image<>::remove(io_ctx, name, pctx);
614  	    tracepoint(librbd, remove_exit, r);
615  	    return r;
616  	  }
617  	
618  	  int RBD::trash_move(IoCtx &io_ctx, const char *name, uint64_t delay) {
619  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
620  	    tracepoint(librbd, trash_move_enter, io_ctx.get_pool_name().c_str(),
621  	               io_ctx.get_id(), name);
622  	    int r = librbd::api::Trash<>::move(io_ctx, RBD_TRASH_IMAGE_SOURCE_USER,
623  	                                       name, delay);
624  	    tracepoint(librbd, trash_move_exit, r);
625  	    return r;
626  	  }
627  	
628  	  int RBD::trash_get(IoCtx &io_ctx, const char *id, trash_image_info_t *info) {
629  	    return librbd::api::Trash<>::get(io_ctx, id, info);
630  	  }
631  	
632  	  int RBD::trash_list(IoCtx &io_ctx, vector<trash_image_info_t> &entries) {
633  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
634  	    tracepoint(librbd, trash_list_enter,
635  	               io_ctx.get_pool_name().c_str(), io_ctx.get_id());
636  	    int r = librbd::api::Trash<>::list(io_ctx, entries, true);
637  	#ifdef WITH_LTTNG
638  	    if (r >= 0) {
639  	      for (const auto& entry : entries) {
640  		tracepoint(librbd, trash_list_entry, entry.id.c_str());
641  	      }
642  	    }
643  	#endif
644  	    tracepoint(librbd, trash_list_exit, r, r);
645  	    return r;
646  	  }
647  	
648  	  int RBD::trash_remove(IoCtx &io_ctx, const char *image_id, bool force) {
649  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
650  	    tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
651  	               io_ctx.get_id(), image_id, force);
652  	    librbd::NoOpProgressContext prog_ctx;
653  	    int r = librbd::api::Trash<>::remove(io_ctx, image_id, force, prog_ctx);
654  	    tracepoint(librbd, trash_remove_exit, r);
655  	    return r;
656  	  }
657  	
658  	  int RBD::trash_remove_with_progress(IoCtx &io_ctx, const char *image_id,
659  	                                      bool force, ProgressContext &pctx) {
660  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
661  	    tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
662  	               io_ctx.get_id(), image_id, force);
663  	    int r = librbd::api::Trash<>::remove(io_ctx, image_id, force, pctx);
664  	    tracepoint(librbd, trash_remove_exit, r);
665  	    return r;
666  	  }
667  	
668  	  int RBD::trash_restore(IoCtx &io_ctx, const char *id, const char *name) {
669  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
670  	    tracepoint(librbd, trash_undelete_enter, io_ctx.get_pool_name().c_str(),
671  	               io_ctx.get_id(), id, name);
672  	    int r = librbd::api::Trash<>::restore(
673  	      io_ctx, librbd::api::Trash<>::RESTORE_SOURCE_WHITELIST, id, name);
674  	    tracepoint(librbd, trash_undelete_exit, r);
675  	    return r;
676  	  }
677  	
678  	  int RBD::trash_purge(IoCtx &io_ctx, time_t expire_ts, float threshold) {
679  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
680  	    tracepoint(librbd, trash_purge_enter, io_ctx.get_pool_name().c_str(),
681  	               io_ctx.get_id(), expire_ts, threshold);
682  	    NoOpProgressContext nop_pctx;
683  	    int r = librbd::api::Trash<>::purge(io_ctx, expire_ts, threshold, nop_pctx);
684  	    tracepoint(librbd, trash_purge_exit, r);
685  	    return r;
686  	  }
687  	
688  	  int RBD::trash_purge_with_progress(IoCtx &io_ctx, time_t expire_ts,
689  	                                     float threshold, ProgressContext &pctx) {
690  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
691  	    tracepoint(librbd, trash_purge_enter, io_ctx.get_pool_name().c_str(),
692  	               io_ctx.get_id(), expire_ts, threshold);
693  	    int r = librbd::api::Trash<>::purge(io_ctx, expire_ts, threshold, pctx);
694  	    tracepoint(librbd, trash_purge_exit, r);
695  	    return r;
696  	  }
697  	
698  	  int RBD::namespace_create(IoCtx& io_ctx, const char *namespace_name) {
699  	    return librbd::api::Namespace<>::create(io_ctx, namespace_name);
700  	  }
701  	
702  	  int RBD::namespace_remove(IoCtx& io_ctx, const char *namespace_name) {
703  	    return librbd::api::Namespace<>::remove(io_ctx, namespace_name);
704  	  }
705  	
706  	  int RBD::namespace_list(IoCtx& io_ctx,
707  	                          std::vector<std::string>* namespace_names) {
708  	    return librbd::api::Namespace<>::list(io_ctx, namespace_names);
709  	  }
710  	
711  	  int RBD::namespace_exists(IoCtx& io_ctx, const char *namespace_name,
712  	                            bool *exists) {
713  	    return librbd::api::Namespace<>::exists(io_ctx, namespace_name, exists);
714  	  }
715  	
716  	  int RBD::pool_init(IoCtx& io_ctx, bool force) {
717  	    return librbd::api::Pool<>::init(io_ctx, force);
718  	  }
719  	
720  	  int RBD::pool_stats_get(IoCtx& io_ctx, PoolStats* stats) {
721  	    auto pool_stat_options =
722  	      reinterpret_cast<librbd::api::Pool<>::StatOptions*>(stats->pool_stats);
723  	    return librbd::api::Pool<>::get_stats(io_ctx, pool_stat_options);
724  	  }
725  	
726  	  int RBD::list(IoCtx& io_ctx, vector<string>& names)
727  	  {
728  	    std::vector<image_spec_t> image_specs;
729  	    int r = list2(io_ctx, &image_specs);
730  	    if (r < 0) {
731  	      return r;
732  	    }
733  	
734  	    names.clear();
735  	    for (auto& it : image_specs) {
736  	      names.push_back(it.name);
737  	    }
738  	    return 0;
739  	  }
740  	
741  	  int RBD::list2(IoCtx& io_ctx, std::vector<image_spec_t> *images)
742  	  {
743  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
744  	    tracepoint(librbd, list_enter, io_ctx.get_pool_name().c_str(),
745  	               io_ctx.get_id());
746  	
747  	    int r = librbd::api::Image<>::list_images(io_ctx, images);
748  	#ifdef WITH_LTTNG
749  	    if (r >= 0) {
750  	      for (auto& it : *images) {
751  	        tracepoint(librbd, list_entry, it.name.c_str());
752  	      }
753  	    }
754  	#endif
755  	    tracepoint(librbd, list_exit, r, r);
756  	    return r;
757  	  }
758  	
759  	  int RBD::rename(IoCtx& src_io_ctx, const char *srcname, const char *destname)
760  	  {
761  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(src_io_ctx));
762  	    tracepoint(librbd, rename_enter, src_io_ctx.get_pool_name().c_str(), src_io_ctx.get_id(), srcname, destname);
763  	    int r = librbd::rename(src_io_ctx, srcname, destname);
764  	    tracepoint(librbd, rename_exit, r);
765  	    return r;
766  	  }
767  	
768  	  int RBD::migration_prepare(IoCtx& io_ctx, const char *image_name,
769  	                             IoCtx& dest_io_ctx, const char *dest_image_name,
770  	                             ImageOptions& opts)
771  	  {
772  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
773  	    tracepoint(librbd, migration_prepare_enter, io_ctx.get_pool_name().c_str(),
774  	               io_ctx.get_id(), image_name, dest_io_ctx.get_pool_name().c_str(),
775  	               dest_io_ctx.get_id(), dest_image_name, opts.opts);
776  	    int r = librbd::api::Migration<>::prepare(io_ctx, image_name, dest_io_ctx,
777  	                                              dest_image_name, opts);
778  	    tracepoint(librbd, migration_prepare_exit, r);
779  	    return r;
780  	  }
781  	
782  	  int RBD::migration_execute(IoCtx& io_ctx, const char *image_name)
783  	  {
784  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
785  	    tracepoint(librbd, migration_execute_enter, io_ctx.get_pool_name().c_str(),
786  	               io_ctx.get_id(), image_name);
787  	    librbd::NoOpProgressContext prog_ctx;
788  	    int r = librbd::api::Migration<>::execute(io_ctx, image_name, prog_ctx);
789  	    tracepoint(librbd, migration_execute_exit, r);
790  	    return r;
791  	  }
792  	
793  	  int RBD::migration_execute_with_progress(IoCtx& io_ctx,
794  	                                           const char *image_name,
795  	                                           librbd::ProgressContext &prog_ctx)
796  	  {
797  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
798  	    tracepoint(librbd, migration_execute_enter, io_ctx.get_pool_name().c_str(),
799  	               io_ctx.get_id(), image_name);
800  	    int r = librbd::api::Migration<>::execute(io_ctx, image_name, prog_ctx);
801  	    tracepoint(librbd, migration_execute_exit, r);
802  	    return r;
803  	  }
804  	
805  	  int RBD::migration_abort(IoCtx& io_ctx, const char *image_name)
806  	  {
807  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
808  	    tracepoint(librbd, migration_abort_enter, io_ctx.get_pool_name().c_str(),
809  	               io_ctx.get_id(), image_name);
810  	    librbd::NoOpProgressContext prog_ctx;
811  	    int r = librbd::api::Migration<>::abort(io_ctx, image_name, prog_ctx);
812  	    tracepoint(librbd, migration_abort_exit, r);
813  	    return r;
814  	  }
815  	
816  	  int RBD::migration_abort_with_progress(IoCtx& io_ctx, const char *image_name,
817  	                                         librbd::ProgressContext &prog_ctx)
818  	  {
819  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
820  	    tracepoint(librbd, migration_abort_enter, io_ctx.get_pool_name().c_str(),
821  	               io_ctx.get_id(), image_name);
822  	    int r = librbd::api::Migration<>::abort(io_ctx, image_name, prog_ctx);
823  	    tracepoint(librbd, migration_abort_exit, r);
824  	    return r;
825  	  }
826  	
827  	  int RBD::migration_commit(IoCtx& io_ctx, const char *image_name)
828  	  {
829  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
830  	    tracepoint(librbd, migration_commit_enter, io_ctx.get_pool_name().c_str(),
831  	               io_ctx.get_id(), image_name);
832  	    librbd::NoOpProgressContext prog_ctx;
833  	    int r = librbd::api::Migration<>::commit(io_ctx, image_name, prog_ctx);
834  	    tracepoint(librbd, migration_commit_exit, r);
835  	    return r;
836  	  }
837  	
838  	  int RBD::migration_commit_with_progress(IoCtx& io_ctx, const char *image_name,
839  	                                          librbd::ProgressContext &prog_ctx)
840  	  {
841  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
842  	    tracepoint(librbd, migration_commit_enter, io_ctx.get_pool_name().c_str(),
843  	               io_ctx.get_id(), image_name);
844  	    int r = librbd::api::Migration<>::commit(io_ctx, image_name, prog_ctx);
845  	    tracepoint(librbd, migration_commit_exit, r);
846  	    return r;
847  	  }
848  	
849  	  int RBD::migration_status(IoCtx& io_ctx, const char *image_name,
850  	                            image_migration_status_t *status,
851  	                            size_t status_size)
852  	  {
853  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
854  	    tracepoint(librbd, migration_status_enter, io_ctx.get_pool_name().c_str(),
855  	               io_ctx.get_id(), image_name);
856  	
857  	    if (status_size != sizeof(image_migration_status_t)) {
858  	      tracepoint(librbd, migration_status_exit, -ERANGE);
859  	      return -ERANGE;
860  	    }
861  	
862  	    int r = librbd::api::Migration<>::status(io_ctx, image_name, status);
863  	    tracepoint(librbd, migration_status_exit, r);
864  	    return r;
865  	  }
866  	
867  	  int RBD::mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode) {
868  	    return librbd::api::Mirror<>::mode_get(io_ctx, mirror_mode);
869  	  }
870  	
871  	  int RBD::mirror_site_name_get(librados::Rados& rados,
872  	                                std::string* site_name) {
873  	    return librbd::api::Mirror<>::site_name_get(rados, site_name);
874  	  }
875  	
876  	  int RBD::mirror_site_name_set(librados::Rados& rados,
877  	                                const std::string& site_name) {
878  	    return librbd::api::Mirror<>::site_name_set(rados, site_name);
879  	  }
880  	
881  	  int RBD::mirror_mode_set(IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode) {
882  	    return librbd::api::Mirror<>::mode_set(io_ctx, mirror_mode);
883  	  }
884  	
885  	  int RBD::mirror_peer_bootstrap_create(IoCtx& io_ctx, std::string* token) {
886  	    return librbd::api::Mirror<>::peer_bootstrap_create(io_ctx, token);
887  	  }
888  	
889  	  int RBD::mirror_peer_bootstrap_import(IoCtx& io_ctx,
890  	                                        rbd_mirror_peer_direction_t direction,
891  	                                        const std::string& token) {
892  	    return librbd::api::Mirror<>::peer_bootstrap_import(io_ctx, direction,
893  	                                                        token);
894  	  }
895  	
896  	  int RBD::mirror_peer_add(IoCtx& io_ctx, std::string *uuid,
897  	                           const std::string &cluster_name,
898  	                           const std::string &client_name) {
899  	    return librbd::api::Mirror<>::peer_add(io_ctx, uuid, cluster_name,
900  	                                           client_name);
901  	  }
902  	
903  	  int RBD::mirror_peer_remove(IoCtx& io_ctx, const std::string &uuid) {
904  	    return librbd::api::Mirror<>::peer_remove(io_ctx, uuid);
905  	  }
906  	
907  	  int RBD::mirror_peer_list(IoCtx& io_ctx, std::vector<mirror_peer_t> *peers) {
908  	    return librbd::api::Mirror<>::peer_list(io_ctx, peers);
909  	  }
910  	
911  	  int RBD::mirror_peer_set_client(IoCtx& io_ctx, const std::string &uuid,
912  	                                  const std::string &client_name) {
913  	    return librbd::api::Mirror<>::peer_set_client(io_ctx, uuid, client_name);
914  	  }
915  	
916  	  int RBD::mirror_peer_set_cluster(IoCtx& io_ctx, const std::string &uuid,
917  	                                   const std::string &cluster_name) {
918  	    return librbd::api::Mirror<>::peer_set_cluster(io_ctx, uuid, cluster_name);
919  	  }
920  	
921  	  int RBD::mirror_peer_get_attributes(
922  	      IoCtx& io_ctx, const std::string &uuid,
923  	      std::map<std::string, std::string> *key_vals) {
924  	    return librbd::api::Mirror<>::peer_get_attributes(io_ctx, uuid, key_vals);
925  	  }
926  	
927  	  int RBD::mirror_peer_set_attributes(
928  	      IoCtx& io_ctx, const std::string &uuid,
929  	      const std::map<std::string, std::string>& key_vals) {
930  	    return librbd::api::Mirror<>::peer_set_attributes(io_ctx, uuid, key_vals);
931  	  }
932  	
933  	  int RBD::mirror_image_status_list(IoCtx& io_ctx, const std::string &start_id,
934  	      size_t max, std::map<std::string, mirror_image_status_t> *images) {
935  	    return librbd::api::Mirror<>::image_status_list(io_ctx, start_id, max,
936  	                                                    images);
937  	  }
938  	
939  	  int RBD::mirror_image_status_summary(IoCtx& io_ctx,
940  	      std::map<mirror_image_status_state_t, int> *states) {
941  	    return librbd::api::Mirror<>::image_status_summary(io_ctx, states);
942  	  }
943  	
944  	  int RBD::mirror_image_instance_id_list(IoCtx& io_ctx,
945  	      const std::string &start_id, size_t max,
946  	      std::map<std::string, std::string> *instance_ids) {
947  	    return librbd::api::Mirror<>::image_instance_id_list(io_ctx, start_id, max,
948  	                                                         instance_ids);
949  	  }
950  	
951  	  int RBD::group_create(IoCtx& io_ctx, const char *group_name)
952  	  {
953  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
954  	    tracepoint(librbd, group_create_enter, io_ctx.get_pool_name().c_str(),
955  		       io_ctx.get_id(), group_name);
956  	    int r = librbd::api::Group<>::create(io_ctx, group_name);
957  	    tracepoint(librbd, group_create_exit, r);
958  	    return r;
959  	  }
960  	
961  	  int RBD::group_remove(IoCtx& io_ctx, const char *group_name)
962  	  {
963  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
964  	    tracepoint(librbd, group_remove_enter, io_ctx.get_pool_name().c_str(),
965  		       io_ctx.get_id(), group_name);
966  	    int r = librbd::api::Group<>::remove(io_ctx, group_name);
967  	    tracepoint(librbd, group_remove_exit, r);
968  	    return r;
969  	  }
970  	
971  	  int RBD::group_list(IoCtx& io_ctx, vector<string> *names)
972  	  {
973  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
974  	    tracepoint(librbd, group_list_enter, io_ctx.get_pool_name().c_str(),
975  		       io_ctx.get_id());
976  	
977  	    int r = librbd::api::Group<>::list(io_ctx, names);
978  	    if (r >= 0) {
979  	      for (auto itr : *names) {
980  		tracepoint(librbd, group_list_entry, itr.c_str());
981  	      }
982  	    }
983  	    tracepoint(librbd, group_list_exit, r);
984  	    return r;
985  	  }
986  	
987  	  int RBD::group_rename(IoCtx& io_ctx, const char *src_name,
988  	                        const char *dest_name)
989  	  {
990  	    TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
991  	    tracepoint(librbd, group_rename_enter, io_ctx.get_pool_name().c_str(),
992  	               io_ctx.get_id(), src_name, dest_name);
993  	    int r = librbd::api::Group<>::rename(io_ctx, src_name, dest_name);
994  	    tracepoint(librbd, group_rename_exit, r);
995  	    return r;
996  	  }
997  	
998  	  int RBD::group_image_add(IoCtx& group_ioctx, const char *group_name,
999  	                           IoCtx& image_ioctx, const char *image_name)
1000 	  {
1001 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1002 	    tracepoint(librbd, group_image_add_enter,
1003 	               group_ioctx.get_pool_name().c_str(),
1004 	               group_ioctx.get_id(), group_name,
1005 	               image_ioctx.get_pool_name().c_str(),
1006 	               image_ioctx.get_id(), image_name);
1007 	    int r = librbd::api::Group<>::image_add(group_ioctx, group_name,
1008 	                                            image_ioctx, image_name);
1009 	    tracepoint(librbd, group_image_add_exit, r);
1010 	    return r;
1011 	  }
1012 	
1013 	  int RBD::group_image_remove(IoCtx& group_ioctx, const char *group_name,
1014 	                              IoCtx& image_ioctx, const char *image_name)
1015 	  {
1016 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1017 	    tracepoint(librbd, group_image_remove_enter,
1018 	               group_ioctx.get_pool_name().c_str(),
1019 	               group_ioctx.get_id(), group_name,
1020 	               image_ioctx.get_pool_name().c_str(),
1021 	               image_ioctx.get_id(), image_name);
1022 	    int r = librbd::api::Group<>::image_remove(group_ioctx, group_name,
1023 	                                               image_ioctx, image_name);
1024 	    tracepoint(librbd, group_image_remove_exit, r);
1025 	    return r;
1026 	  }
1027 	
1028 	  int RBD::group_image_remove_by_id(IoCtx& group_ioctx, const char *group_name,
1029 	                                    IoCtx& image_ioctx, const char *image_id)
1030 	  {
1031 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1032 	    tracepoint(librbd, group_image_remove_by_id_enter,
1033 	               group_ioctx.get_pool_name().c_str(),
1034 	               group_ioctx.get_id(), group_name,
1035 	               image_ioctx.get_pool_name().c_str(),
1036 	               image_ioctx.get_id(), image_id);
1037 	    int r = librbd::api::Group<>::image_remove_by_id(group_ioctx, group_name,
1038 	                                                     image_ioctx, image_id);
1039 	    tracepoint(librbd, group_image_remove_by_id_exit, r);
1040 	    return r;
1041 	  }
1042 	
1043 	  int RBD::group_image_list(IoCtx& group_ioctx, const char *group_name,
1044 	                            std::vector<group_image_info_t> *images,
1045 	                            size_t group_image_info_size)
1046 	  {
1047 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1048 	    tracepoint(librbd, group_image_list_enter,
1049 	               group_ioctx.get_pool_name().c_str(),
1050 		       group_ioctx.get_id(), group_name);
1051 	
1052 	    if (group_image_info_size != sizeof(group_image_info_t)) {
1053 	      tracepoint(librbd, group_image_list_exit, -ERANGE);
1054 	      return -ERANGE;
1055 	    }
1056 	
1057 	    int r = librbd::api::Group<>::image_list(group_ioctx, group_name, images);
1058 	    tracepoint(librbd, group_image_list_exit, r);
1059 	    return r;
1060 	  }
1061 	
1062 	  int RBD::group_snap_create(IoCtx& group_ioctx, const char *group_name,
1063 				     const char *snap_name) {
1064 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1065 	    tracepoint(librbd, group_snap_create_enter,
1066 	               group_ioctx.get_pool_name().c_str(),
1067 		       group_ioctx.get_id(), group_name, snap_name);
1068 	    int r = librbd::api::Group<>::snap_create(group_ioctx, group_name,
1069 	                                              snap_name);
1070 	    tracepoint(librbd, group_snap_create_exit, r);
1071 	    return r;
1072 	  }
1073 	
1074 	  int RBD::group_snap_remove(IoCtx& group_ioctx, const char *group_name,
1075 				     const char *snap_name) {
1076 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1077 	    tracepoint(librbd, group_snap_remove_enter,
1078 	               group_ioctx.get_pool_name().c_str(),
1079 		       group_ioctx.get_id(), group_name, snap_name);
1080 	    int r = librbd::api::Group<>::snap_remove(group_ioctx, group_name,
1081 	                                              snap_name);
1082 	    tracepoint(librbd, group_snap_remove_exit, r);
1083 	    return r;
1084 	  }
1085 	
1086 	  int RBD::group_snap_list(IoCtx& group_ioctx, const char *group_name,
1087 				   std::vector<group_snap_info_t> *snaps,
1088 	                           size_t group_snap_info_size)
1089 	  {
1090 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1091 	    tracepoint(librbd, group_snap_list_enter,
1092 	               group_ioctx.get_pool_name().c_str(),
1093 		       group_ioctx.get_id(), group_name);
1094 	
1095 	    if (group_snap_info_size != sizeof(group_snap_info_t)) {
1096 	      tracepoint(librbd, group_snap_list_exit, -ERANGE);
1097 	      return -ERANGE;
1098 	    }
1099 	
1100 	    int r = librbd::api::Group<>::snap_list(group_ioctx, group_name, snaps);
1101 	    tracepoint(librbd, group_snap_list_exit, r);
1102 	    return r;
1103 	  }
1104 	
1105 	  int RBD::group_snap_rename(IoCtx& group_ioctx, const char *group_name,
1106 	                             const char *old_snap_name,
1107 	                             const char *new_snap_name)
1108 	  {
1109 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1110 	    tracepoint(librbd, group_snap_rename_enter,
1111 	               group_ioctx.get_pool_name().c_str(), group_ioctx.get_id(),
1112 	               group_name, old_snap_name, new_snap_name);
1113 	    int r = librbd::api::Group<>::snap_rename(group_ioctx, group_name,
1114 	                                              old_snap_name, new_snap_name);
1115 	    tracepoint(librbd, group_snap_list_exit, r);
1116 	    return r;
1117 	  }
1118 	
1119 	  int RBD::group_snap_rollback(IoCtx& group_ioctx, const char *group_name,
1120 	                               const char *snap_name) {
1121 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1122 	    tracepoint(librbd, group_snap_rollback_enter,
1123 	               group_ioctx.get_pool_name().c_str(),
1124 	               group_ioctx.get_id(), group_name, snap_name);
1125 	    librbd::NoOpProgressContext prog_ctx;
1126 	    int r = librbd::api::Group<>::snap_rollback(group_ioctx, group_name,
1127 	                                                snap_name, prog_ctx);
1128 	    tracepoint(librbd, group_snap_rollback_exit, r);
1129 	    return r;
1130 	  }
1131 	
1132 	  int RBD::group_snap_rollback_with_progress(IoCtx& group_ioctx,
1133 	                                             const char *group_name,
1134 	                                             const char *snap_name,
1135 	                                             ProgressContext& prog_ctx) {
1136 	    TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
1137 	    tracepoint(librbd, group_snap_rollback_enter,
1138 	               group_ioctx.get_pool_name().c_str(),
1139 	               group_ioctx.get_id(), group_name, snap_name);
1140 	    int r = librbd::api::Group<>::snap_rollback(group_ioctx, group_name,
1141 	                                                snap_name, prog_ctx);
1142 	    tracepoint(librbd, group_snap_rollback_exit, r);
1143 	    return r;
1144 	  }
1145 	
1146 	  int RBD::pool_metadata_get(IoCtx& ioctx, const std::string &key,
1147 	                             std::string *value)
1148 	  {
1149 	    int r = librbd::api::PoolMetadata<>::get(ioctx, key, value);
1150 	    return r;
1151 	  }
1152 	
1153 	  int RBD::pool_metadata_set(IoCtx& ioctx, const std::string &key,
1154 	                             const std::string &value)
1155 	  {
1156 	    int r = librbd::api::PoolMetadata<>::set(ioctx, key, value);
1157 	    return r;
1158 	  }
1159 	
1160 	  int RBD::pool_metadata_remove(IoCtx& ioctx, const std::string &key)
1161 	  {
1162 	    int r = librbd::api::PoolMetadata<>::remove(ioctx, key);
1163 	    return r;
1164 	  }
1165 	
1166 	  int RBD::pool_metadata_list(IoCtx& ioctx, const std::string &start,
1167 	                              uint64_t max, map<string, bufferlist> *pairs)
1168 	  {
1169 	    int r = librbd::api::PoolMetadata<>::list(ioctx, start, max, pairs);
1170 	    return r;
1171 	  }
1172 	
1173 	  int RBD::config_list(IoCtx& io_ctx, std::vector<config_option_t> *options) {
1174 	    return librbd::api::Config<>::list(io_ctx, options);
1175 	  }
1176 	
1177 	  RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb)
1178 	  {
1179 	    auto aio_comp = librbd::io::AioCompletion::create(
1180 	      cb_arg, complete_cb, this);
1181 	    aio_comp->external_callback = true;
1182 	    pc = reinterpret_cast<void*>(aio_comp);
1183 	  }
1184 	
1185 	  bool RBD::AioCompletion::is_complete()
1186 	  {
1187 	    librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
1188 	    return c->is_complete();
1189 	  }
1190 	
1191 	  int RBD::AioCompletion::wait_for_complete()
1192 	  {
1193 	    librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
1194 	    return c->wait_for_complete();
1195 	  }
1196 	
1197 	  ssize_t RBD::AioCompletion::get_return_value()
1198 	  {
1199 	    librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
1200 	    return c->get_return_value();
1201 	  }
1202 	
1203 	  void *RBD::AioCompletion::get_arg()
1204 	  {
1205 	    librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
1206 	    return c->get_arg();
1207 	  }
1208 	
1209 	  void RBD::AioCompletion::release()
1210 	  {
1211 	    librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
1212 	    c->release();
1213 	    delete this;
1214 	  }
1215 	
1216 	  /*
1217 	    ImageOptions
1218 	  */
1219 	
1220 	  ImageOptions::ImageOptions()
1221 	  {
1222 	    librbd::image_options_create(&opts);
1223 	  }
1224 	
1225 	  ImageOptions::ImageOptions(rbd_image_options_t opts_)
1226 	  {
1227 	    librbd::image_options_create_ref(&opts, opts_);
1228 	  }
1229 	
1230 	  ImageOptions::ImageOptions(const ImageOptions &imgopts)
1231 	  {
1232 	    librbd::image_options_copy(&opts, imgopts);
1233 	  }
1234 	
1235 	  ImageOptions::~ImageOptions()
1236 	  {
1237 	    librbd::image_options_destroy(opts);
1238 	  }
1239 	
1240 	  int ImageOptions::set(int optname, const std::string& optval)
1241 	  {
1242 	    return librbd::image_options_set(opts, optname, optval);
1243 	  }
1244 	
1245 	  int ImageOptions::set(int optname, uint64_t optval)
1246 	  {
1247 	    return librbd::image_options_set(opts, optname, optval);
1248 	  }
1249 	
1250 	  int ImageOptions::get(int optname, std::string* optval) const
1251 	  {
1252 	    return librbd::image_options_get(opts, optname, optval);
1253 	  }
1254 	
1255 	  int ImageOptions::get(int optname, uint64_t* optval) const
1256 	  {
1257 	    return librbd::image_options_get(opts, optname, optval);
1258 	  }
1259 	
1260 	  int ImageOptions::is_set(int optname, bool* is_set)
1261 	  {
1262 	    return librbd::image_options_is_set(opts, optname, is_set);
1263 	  }
1264 	
1265 	  int ImageOptions::unset(int optname)
1266 	  {
1267 	    return librbd::image_options_unset(opts, optname);
1268 	  }
1269 	
1270 	  void ImageOptions::clear()
1271 	  {
1272 	    librbd::image_options_clear(opts);
1273 	  }
1274 	
1275 	  bool ImageOptions::empty() const
1276 	  {
1277 	    return librbd::image_options_is_empty(opts);
1278 	  }
1279 	
1280 	  /*
1281 	    Image
1282 	  */
1283 	
1284 	  Image::Image() : ctx(NULL)
1285 	  {
1286 	  }
1287 	
1288 	  Image::~Image()
1289 	  {
1290 	    close();
1291 	  }
1292 	
1293 	  int Image::close()
1294 	  {
1295 	    int r = 0;
1296 	    if (ctx) {
1297 	      ImageCtx *ictx = (ImageCtx *)ctx;
1298 	      tracepoint(librbd, close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
1299 	
1300 	      r = ictx->state->close();
1301 	      ctx = NULL;
1302 	
1303 	      tracepoint(librbd, close_image_exit, r);
1304 	    }
1305 	    return r;
1306 	  }
1307 	
1308 	  int Image::aio_close(RBD::AioCompletion *c)
1309 	  {
1310 	    if (!ctx) {
1311 	      return -EINVAL;
1312 	    }
1313 	
1314 	    ImageCtx *ictx = (ImageCtx *)ctx;
1315 	    tracepoint(librbd, aio_close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), c->pc);
1316 	
1317 	    ictx->state->close(new C_AioCompletion(ictx, librbd::io::AIO_TYPE_CLOSE,
1318 	                                           get_aio_completion(c)));
1319 	    ctx = NULL;
1320 	
1321 	    tracepoint(librbd, aio_close_image_exit, 0);
1322 	    return 0;
1323 	  }
1324 	
1325 	  int Image::resize(uint64_t size)
1326 	  {
1327 	    ImageCtx *ictx = (ImageCtx *)ctx;
1328 	    tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
1329 	    librbd::NoOpProgressContext prog_ctx;
1330 	    int r = ictx->operations->resize(size, true, prog_ctx);
1331 	    tracepoint(librbd, resize_exit, r);
1332 	    return r;
1333 	  }
1334 	
1335 	  int Image::resize2(uint64_t size, bool allow_shrink, librbd::ProgressContext& pctx)
1336 	  {
1337 	    ImageCtx *ictx = (ImageCtx *)ctx;
1338 	    tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
1339 	    int r = ictx->operations->resize(size, allow_shrink, pctx);
1340 	    tracepoint(librbd, resize_exit, r);
1341 	    return r;
1342 	  }
1343 	
1344 	  int Image::resize_with_progress(uint64_t size, librbd::ProgressContext& pctx)
1345 	  {
1346 	    ImageCtx *ictx = (ImageCtx *)ctx;
1347 	    tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
1348 	    int r = ictx->operations->resize(size, true, pctx);
1349 	    tracepoint(librbd, resize_exit, r);
1350 	    return r;
1351 	  }
1352 	
1353 	  int Image::stat(image_info_t& info, size_t infosize)
1354 	  {
1355 	    ImageCtx *ictx = (ImageCtx *)ctx;
1356 	    tracepoint(librbd, stat_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1357 	    int r = librbd::info(ictx, info, infosize);
1358 	    tracepoint(librbd, stat_exit, r, &info);
1359 	    return r;
1360 	  }
1361 	
1362 	  int Image::old_format(uint8_t *old)
1363 	  {
1364 	    ImageCtx *ictx = (ImageCtx *)ctx;
1365 	    tracepoint(librbd, get_old_format_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1366 	    int r = librbd::get_old_format(ictx, old);
1367 	    tracepoint(librbd, get_old_format_exit, r, *old);
1368 	    return r;
1369 	  }
1370 	
1371 	  int Image::size(uint64_t *size)
1372 	  {
1373 	    ImageCtx *ictx = (ImageCtx *)ctx;
1374 	    tracepoint(librbd, get_size_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1375 	    int r = librbd::get_size(ictx, size);
1376 	    tracepoint(librbd, get_size_exit, r, *size);
1377 	    return r;
1378 	  }
1379 	
1380 	  int Image::get_group(group_info_t *group_info, size_t group_info_size)
1381 	  {
1382 	    ImageCtx *ictx = (ImageCtx *)ctx;
1383 	    tracepoint(librbd, image_get_group_enter, ictx->name.c_str());
1384 	
1385 	    if (group_info_size != sizeof(group_info_t)) {
1386 	      tracepoint(librbd, image_get_group_exit, -ERANGE);
1387 	      return -ERANGE;
1388 	    }
1389 	
1390 	    int r = librbd::api::Group<>::image_get_group(ictx, group_info);
1391 	    tracepoint(librbd, image_get_group_exit, r);
1392 	    return r;
1393 	  }
1394 	
1395 	  int Image::features(uint64_t *features)
1396 	  {
1397 	    ImageCtx *ictx = (ImageCtx *)ctx;
1398 	    tracepoint(librbd, get_features_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1399 	    int r = librbd::get_features(ictx, features);
1400 	    tracepoint(librbd, get_features_exit, r, *features);
1401 	    return r;
1402 	  }
1403 	
1404 	  int Image::update_features(uint64_t features, bool enabled)
1405 	  {
1406 	    ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
1407 	    tracepoint(librbd, update_features_enter, ictx, features, enabled);
1408 	    int r = ictx->operations->update_features(features, enabled);
1409 	    tracepoint(librbd, update_features_exit, r);
1410 	    return r;
1411 	  }
1412 	
1413 	  int Image::get_op_features(uint64_t *op_features)
1414 	  {
1415 	    ImageCtx *ictx = (ImageCtx *)ctx;
1416 	    return librbd::api::Image<>::get_op_features(ictx, op_features);
1417 	  }
1418 	
1419 	  uint64_t Image::get_stripe_unit() const
1420 	  {
1421 	    ImageCtx *ictx = (ImageCtx *)ctx;
1422 	    tracepoint(librbd, get_stripe_unit_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1423 	    uint64_t stripe_unit = ictx->get_stripe_unit();
1424 	    tracepoint(librbd, get_stripe_unit_exit, 0, stripe_unit);
1425 	    return stripe_unit;
1426 	  }
1427 	
1428 	  uint64_t Image::get_stripe_count() const
1429 	  {
1430 	    ImageCtx *ictx = (ImageCtx *)ctx;
1431 	    tracepoint(librbd, get_stripe_count_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1432 	    uint64_t stripe_count = ictx->get_stripe_count();
1433 	    tracepoint(librbd, get_stripe_count_exit, 0, stripe_count);
1434 	    return stripe_count;
1435 	  }
1436 	
1437 	  int Image::get_create_timestamp(struct timespec *timestamp)
1438 	  {
1439 	    ImageCtx *ictx = (ImageCtx *)ctx;
1440 	    tracepoint(librbd, get_create_timestamp_enter, ictx, ictx->name.c_str(),
1441 	               ictx->read_only);
1442 	    utime_t time = ictx->get_create_timestamp();
1443 	    time.to_timespec(timestamp);
1444 	    tracepoint(librbd, get_create_timestamp_exit, 0, timestamp);
1445 	    return 0;
1446 	  }
1447 	
1448 	  int Image::get_access_timestamp(struct timespec *timestamp)
1449 	  {
1450 	    ImageCtx *ictx = (ImageCtx *)ctx;
1451 	    tracepoint(librbd, get_access_timestamp_enter, ictx, ictx->name.c_str(),
1452 	               ictx->read_only);
1453 	    {
1454 	      std::shared_lock timestamp_locker{ictx->timestamp_lock};
1455 	      utime_t time = ictx->get_access_timestamp();
1456 	      time.to_timespec(timestamp);
1457 	    }
1458 	    tracepoint(librbd, get_access_timestamp_exit, 0, timestamp);
1459 	    return 0;
1460 	  }
1461 	
1462 	  int Image::get_modify_timestamp(struct timespec *timestamp)
1463 	  {
1464 	    ImageCtx *ictx = (ImageCtx *)ctx;
1465 	    tracepoint(librbd, get_modify_timestamp_enter, ictx, ictx->name.c_str(),
1466 	               ictx->read_only);
1467 	    {
1468 	      std::shared_lock timestamp_locker{ictx->timestamp_lock};
1469 	      utime_t time = ictx->get_modify_timestamp();
1470 	      time.to_timespec(timestamp);
1471 	    }
1472 	    tracepoint(librbd, get_modify_timestamp_exit, 0, timestamp);
1473 	    return 0;
1474 	  }
1475 	
1476 	  int Image::overlap(uint64_t *overlap)
1477 	  {
1478 	    ImageCtx *ictx = (ImageCtx *)ctx;
1479 	    tracepoint(librbd, get_overlap_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1480 	    int r = librbd::get_overlap(ictx, overlap);
1481 	    tracepoint(librbd, get_overlap_exit, r, *overlap);
1482 	    return r;
1483 	  }
1484 	
1485 	  int Image::get_name(std::string *name)
1486 	  {
1487 	    ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
1488 	    *name = ictx->name;
1489 	    return 0;
1490 	  }
1491 	
1492 	  int Image::get_id(std::string *id)
1493 	  {
1494 	    ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
1495 	    if (ictx->old_format) {
1496 	      return -EINVAL;
1497 	    }
1498 	    *id = ictx->id;
1499 	    return 0;
1500 	  }
1501 	
1502 	  std::string Image::get_block_name_prefix()
1503 	  {
1504 	    ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
1505 	    return ictx->object_prefix;
1506 	  }
1507 	
1508 	  int64_t Image::get_data_pool_id()
1509 	  {
1510 	    ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
1511 	    return librbd::api::Image<>::get_data_pool_id(ictx);
1512 	  }
1513 	
1514 	  int Image::parent_info(string *parent_pool_name, string *parent_name,
1515 				 string *parent_snap_name)
1516 	  {
1517 	    librbd::linked_image_spec_t parent_image;
1518 	    librbd::snap_spec_t parent_snap;
1519 	    int r = get_parent(&parent_image, &parent_snap);
1520 	    if (r >= 0) {
1521 	      if (parent_pool_name != nullptr) {
1522 	        *parent_pool_name = parent_image.pool_name;
1523 	      }
1524 	      if (parent_name != nullptr) {
1525 	        *parent_name = parent_image.image_name;
1526 	      }
1527 	      if (parent_snap_name != nullptr) {
1528 	        *parent_snap_name = parent_snap.name;
1529 	      }
1530 	    }
1531 	    return r;
1532 	  }
1533 	
1534 	  int Image::parent_info2(string *parent_pool_name, string *parent_name,
1535 	                          string *parent_id, string *parent_snap_name)
1536 	  {
1537 	    librbd::linked_image_spec_t parent_image;
1538 	    librbd::snap_spec_t parent_snap;
1539 	    int r = get_parent(&parent_image, &parent_snap);
1540 	    if (r >= 0) {
1541 	      if (parent_pool_name != nullptr) {
1542 	        *parent_pool_name = parent_image.pool_name;
1543 	      }
1544 	      if (parent_name != nullptr) {
1545 	        *parent_name = parent_image.image_name;
1546 	      }
1547 	      if (parent_id != nullptr) {
1548 	        *parent_id = parent_image.image_id;
1549 	      }
1550 	      if (parent_snap_name != nullptr) {
1551 	        *parent_snap_name = parent_snap.name;
1552 	      }
1553 	    }
1554 	    return r;
1555 	  }
1556 	
1557 	  int Image::get_parent(linked_image_spec_t *parent_image,
1558 	                        snap_spec_t *parent_snap)
1559 	  {
1560 	    auto ictx = reinterpret_cast<ImageCtx*>(ctx);
1561 	    tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
1562 	               ictx->snap_name.c_str(), ictx->read_only);
1563 	
1564 	    int r = librbd::api::Image<>::get_parent(ictx, parent_image, parent_snap);
1565 	
1566 	    tracepoint(librbd, get_parent_info_exit, r,
1567 	               parent_image->pool_name.c_str(),
1568 	               parent_image->image_name.c_str(),
1569 	               parent_image->image_id.c_str(),
1570 	               parent_snap->name.c_str());
1571 	    return r;
1572 	  }
1573 	
1574 	  int Image::get_flags(uint64_t *flags)
1575 	  {
1576 	    ImageCtx *ictx = (ImageCtx *)ctx;
1577 	    tracepoint(librbd, get_flags_enter, ictx);
1578 	    int r = librbd::get_flags(ictx, flags);
1579 	    tracepoint(librbd, get_flags_exit, ictx, r, *flags);
1580 	    return r;
1581 	  }
1582 	
1583 	  int Image::set_image_notification(int fd, int type)
1584 	  {
1585 	    ImageCtx *ictx = (ImageCtx *)ctx;
1586 	    tracepoint(librbd, set_image_notification_enter, ictx, fd, type);
1587 	    int r = librbd::set_image_notification(ictx, fd, type);
1588 	    tracepoint(librbd, set_image_notification_exit, ictx, r);
1589 	    return r;
1590 	  }
1591 	
1592 	  int Image::is_exclusive_lock_owner(bool *is_owner)
1593 	  {
1594 	    ImageCtx *ictx = (ImageCtx *)ctx;
1595 	    tracepoint(librbd, is_exclusive_lock_owner_enter, ictx);
1596 	    int r = librbd::is_exclusive_lock_owner(ictx, is_owner);
1597 	    tracepoint(librbd, is_exclusive_lock_owner_exit, ictx, r, *is_owner);
1598 	    return r;
1599 	  }
1600 	
1601 	  int Image::lock_acquire(rbd_lock_mode_t lock_mode)
1602 	  {
1603 	    ImageCtx *ictx = (ImageCtx *)ctx;
1604 	    tracepoint(librbd, lock_acquire_enter, ictx, lock_mode);
1605 	    int r = librbd::lock_acquire(ictx, lock_mode);
1606 	    tracepoint(librbd, lock_acquire_exit, ictx, r);
1607 	    return r;
1608 	  }
1609 	
1610 	  int Image::lock_release()
1611 	  {
1612 	    ImageCtx *ictx = (ImageCtx *)ctx;
1613 	    tracepoint(librbd, lock_release_enter, ictx);
1614 	    int r = librbd::lock_release(ictx);
1615 	    tracepoint(librbd, lock_release_exit, ictx, r);
1616 	    return r;
1617 	  }
1618 	
1619 	  int Image::lock_get_owners(rbd_lock_mode_t *lock_mode,
1620 	                             std::list<std::string> *lock_owners)
1621 	  {
1622 	    ImageCtx *ictx = (ImageCtx *)ctx;
1623 	    tracepoint(librbd, lock_get_owners_enter, ictx);
1624 	    int r = librbd::lock_get_owners(ictx, lock_mode, lock_owners);
1625 	    tracepoint(librbd, lock_get_owners_exit, ictx, r);
1626 	    return r;
1627 	  }
1628 	
1629 	  int Image::lock_break(rbd_lock_mode_t lock_mode,
1630 	                        const std::string &lock_owner)
1631 	  {
1632 	    ImageCtx *ictx = (ImageCtx *)ctx;
1633 	    tracepoint(librbd, lock_break_enter, ictx, lock_mode, lock_owner.c_str());
1634 	    int r = librbd::lock_break(ictx, lock_mode, lock_owner);
1635 	    tracepoint(librbd, lock_break_exit, ictx, r);
1636 	    return r;
1637 	  }
1638 	
1639 	  int Image::rebuild_object_map(ProgressContext &prog_ctx)
1640 	  {
1641 	    ImageCtx *ictx = reinterpret_cast<ImageCtx*>(ctx);
1642 	    return ictx->operations->rebuild_object_map(prog_ctx);
1643 	  }
1644 	
1645 	  int Image::check_object_map(ProgressContext &prog_ctx)
1646 	  {
1647 	    ImageCtx *ictx = reinterpret_cast<ImageCtx*>(ctx);
1648 	    return ictx->operations->check_object_map(prog_ctx);
1649 	  }
1650 	
1651 	  int Image::copy(IoCtx& dest_io_ctx, const char *destname)
1652 	  {
1653 	    ImageCtx *ictx = (ImageCtx *)ctx;
1654 	    tracepoint(librbd, copy_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname);
1655 	    ImageOptions opts;
1656 	    librbd::NoOpProgressContext prog_ctx;
1657 	    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, 0);
1658 	    tracepoint(librbd, copy_exit, r);
1659 	    return r;
1660 	  }
1661 	
1662 	  int Image::copy2(Image& dest)
1663 	  {
1664 	    ImageCtx *srcctx = (ImageCtx *)ctx;
1665 	    ImageCtx *destctx = (ImageCtx *)dest.ctx;
1666 	    tracepoint(librbd, copy2_enter, srcctx, srcctx->name.c_str(), srcctx->snap_name.c_str(), srcctx->read_only, destctx, destctx->name.c_str(), destctx->snap_name.c_str(), destctx->read_only);
1667 	    librbd::NoOpProgressContext prog_ctx;
1668 	    int r = librbd::copy(srcctx, destctx, prog_ctx, 0);
1669 	    tracepoint(librbd, copy2_exit, r);
1670 	    return r;
1671 	  }
1672 	
1673 	  int Image::copy3(IoCtx& dest_io_ctx, const char *destname, ImageOptions& opts)
1674 	  {
1675 	    ImageCtx *ictx = (ImageCtx *)ctx;
1676 	    tracepoint(librbd, copy3_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, opts.opts);
1677 	    librbd::NoOpProgressContext prog_ctx;
1678 	    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, 0);
1679 	    tracepoint(librbd, copy3_exit, r);
1680 	    return r;
1681 	  }
1682 	
1683 	  int Image::copy4(IoCtx& dest_io_ctx, const char *destname, ImageOptions& opts, size_t sparse_size)
1684 	  {
1685 	    ImageCtx *ictx = (ImageCtx *)ctx;
1686 	    tracepoint(librbd, copy4_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, opts.opts, sparse_size);
1687 	    librbd::NoOpProgressContext prog_ctx;
1688 	    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, sparse_size);
1689 	    tracepoint(librbd, copy4_exit, r);
1690 	    return r;
1691 	  }
1692 	
1693 	  int Image::copy_with_progress(IoCtx& dest_io_ctx, const char *destname,
1694 					librbd::ProgressContext &pctx)
1695 	  {
1696 	    ImageCtx *ictx = (ImageCtx *)ctx;
1697 	    tracepoint(librbd, copy_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname);
1698 	    ImageOptions opts;
1699 	    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, pctx, 0);
1700 	    tracepoint(librbd, copy_exit, r);
1701 	    return r;
1702 	  }
1703 	
1704 	  int Image::copy_with_progress2(Image& dest, librbd::ProgressContext &pctx)
1705 	  {
1706 	    ImageCtx *srcctx = (ImageCtx *)ctx;
1707 	    ImageCtx *destctx = (ImageCtx *)dest.ctx;
1708 	    tracepoint(librbd, copy2_enter, srcctx, srcctx->name.c_str(), srcctx->snap_name.c_str(), srcctx->read_only, destctx, destctx->name.c_str(), destctx->snap_name.c_str(), destctx->read_only);
1709 	    int r = librbd::copy(srcctx, destctx, pctx, 0);
1710 	    tracepoint(librbd, copy2_exit, r);
1711 	    return r;
1712 	  }
1713 	
1714 	  int Image::copy_with_progress3(IoCtx& dest_io_ctx, const char *destname,
1715 					 ImageOptions& opts,
1716 					 librbd::ProgressContext &pctx)
1717 	  {
1718 	    ImageCtx *ictx = (ImageCtx *)ctx;
1719 	    tracepoint(librbd, copy3_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, opts.opts);
1720 	    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, pctx, 0);
1721 	    tracepoint(librbd, copy3_exit, r);
1722 	    return r;
1723 	  }
1724 	
1725 	  int Image::copy_with_progress4(IoCtx& dest_io_ctx, const char *destname,
1726 					 ImageOptions& opts,
1727 					 librbd::ProgressContext &pctx,
1728 					 size_t sparse_size)
1729 	  {
1730 	    ImageCtx *ictx = (ImageCtx *)ctx;
1731 	    tracepoint(librbd, copy4_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, opts.opts, sparse_size);
1732 	    int r = librbd::copy(ictx, dest_io_ctx, destname, opts, pctx, sparse_size);
1733 	    tracepoint(librbd, copy4_exit, r);
1734 	    return r;
1735 	  }
1736 	
1737 	  int Image::deep_copy(IoCtx& dest_io_ctx, const char *destname,
1738 	                       ImageOptions& opts)
1739 	  {
1740 	    ImageCtx *ictx = (ImageCtx *)ctx;
1741 	    tracepoint(librbd, deep_copy_enter, ictx, ictx->name.c_str(),
1742 	               ictx->snap_name.c_str(), ictx->read_only,
1743 	               dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(),
1744 	               destname, opts.opts);
1745 	    librbd::NoOpProgressContext prog_ctx;
1746 	    int r = librbd::api::Image<>::deep_copy(ictx, dest_io_ctx, destname, opts,
1747 	                                            prog_ctx);
1748 	    tracepoint(librbd, deep_copy_exit, r);
1749 	    return r;
1750 	  }
1751 	
1752 	  int Image::deep_copy_with_progress(IoCtx& dest_io_ctx, const char *destname,
1753 	                                     ImageOptions& opts,
1754 	                                     librbd::ProgressContext &prog_ctx)
1755 	  {
1756 	    ImageCtx *ictx = (ImageCtx *)ctx;
1757 	    tracepoint(librbd, deep_copy_enter, ictx, ictx->name.c_str(),
1758 	               ictx->snap_name.c_str(), ictx->read_only,
1759 	               dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(),
1760 	               destname, opts.opts);
1761 	    int r = librbd::api::Image<>::deep_copy(ictx, dest_io_ctx, destname, opts,
1762 	                                            prog_ctx);
1763 	    tracepoint(librbd, deep_copy_exit, r);
1764 	    return r;
1765 	  }
1766 	
1767 	  int Image::flatten()
1768 	  {
1769 	    ImageCtx *ictx = (ImageCtx *)ctx;
1770 	    tracepoint(librbd, flatten_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
1771 	    librbd::NoOpProgressContext prog_ctx;
1772 	    int r = ictx->operations->flatten(prog_ctx);
1773 	    tracepoint(librbd, flatten_exit, r);
1774 	    return r;
1775 	  }
1776 	
1777 	  int Image::flatten_with_progress(librbd::ProgressContext& prog_ctx)
1778 	  {
1779 	    ImageCtx *ictx = (ImageCtx *)ctx;
1780 	    tracepoint(librbd, flatten_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
1781 	    int r = ictx->operations->flatten(prog_ctx);
1782 	    tracepoint(librbd, flatten_exit, r);
1783 	    return r;
1784 	  }
1785 	
1786 	  int Image::sparsify(size_t sparse_size)
1787 	  {
1788 	    ImageCtx *ictx = (ImageCtx *)ctx;
1789 	    tracepoint(librbd, sparsify_enter, ictx, ictx->name.c_str(), sparse_size,
1790 	               ictx->id.c_str());
1791 	    librbd::NoOpProgressContext prog_ctx;
1792 	    int r = ictx->operations->sparsify(sparse_size, prog_ctx);
1793 	    tracepoint(librbd, sparsify_exit, r);
1794 	    return r;
1795 	  }
1796 	
1797 	  int Image::sparsify_with_progress(size_t sparse_size,
1798 	                                    librbd::ProgressContext& prog_ctx)
1799 	  {
1800 	    ImageCtx *ictx = (ImageCtx *)ctx;
1801 	    tracepoint(librbd, sparsify_enter, ictx, ictx->name.c_str(), sparse_size,
1802 	               ictx->id.c_str());
1803 	    int r = ictx->operations->sparsify(sparse_size, prog_ctx);
1804 	    tracepoint(librbd, sparsify_exit, r);
1805 	    return r;
1806 	  }
1807 	
1808 	  int Image::list_children(set<pair<string, string> > *children)
1809 	  {
1810 	    std::vector<linked_image_spec_t> images;
1811 	    int r = list_children3(&images);
1812 	    if (r < 0) {
1813 	      return r;
1814 	    }
1815 	
1816 	    for (auto& image : images) {
1817 	      if (!image.trash) {
1818 	        children->insert({image.pool_name, image.image_name});
1819 	      }
1820 	    }
1821 	    return 0;
1822 	  }
1823 	
1824 	  int Image::list_children2(vector<librbd::child_info_t> *children)
1825 	  {
1826 	    std::vector<linked_image_spec_t> images;
1827 	    int r = list_children3(&images);
1828 	    if (r < 0) {
1829 	      return r;
1830 	    }
1831 	
1832 	    for (auto& image : images) {
1833 	      children->push_back({
1834 	        .pool_name = image.pool_name,
1835 	        .image_name = image.image_name,
1836 	        .image_id = image.image_id,
1837 	        .trash = image.trash});
1838 	    }
1839 	
1840 	    return 0;
1841 	  }
1842 	
1843 	  int Image::list_children3(std::vector<linked_image_spec_t> *images)
1844 	  {
1845 	    auto ictx = reinterpret_cast<ImageCtx*>(ctx);
1846 	    tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(),
1847 	               ictx->snap_name.c_str(), ictx->read_only);
1848 	
1849 	    int r = librbd::api::Image<>::list_children(ictx, images);
1850 	#ifdef WITH_LTTNG
1851 	    if (r >= 0) {
1852 	      for (auto& it : *images) {
1853 	        tracepoint(librbd, list_children_entry, it.pool_name.c_str(),
1854 	                   it.image_name.c_str());
1855 	      }
1856 	    }
1857 	#endif
1858 	    tracepoint(librbd, list_children_exit, r);
1859 	    return r;
1860 	  }
1861 	
1862 	  int Image::list_descendants(std::vector<linked_image_spec_t> *images)
1863 	  {
1864 	    auto ictx = reinterpret_cast<ImageCtx*>(ctx);
1865 	
1866 	    images->clear();
1867 	    int r = librbd::api::Image<>::list_descendants(ictx, {}, images);
1868 	    return r;
1869 	  }
1870 	
1871 	  int Image::list_lockers(std::list<librbd::locker_t> *lockers,
1872 				  bool *exclusive, string *tag)
1873 	  {
1874 	    ImageCtx *ictx = (ImageCtx *)ctx;
1875 	    tracepoint(librbd, list_lockers_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1876 	    int r = librbd::list_lockers(ictx, lockers, exclusive, tag);
1877 	    if (r >= 0) {
1878 	      for (std::list<librbd::locker_t>::const_iterator it = lockers->begin();
1879 		   it != lockers->end(); ++it) {
1880 		tracepoint(librbd, list_lockers_entry, it->client.c_str(), it->cookie.c_str(), it->address.c_str());
1881 	      }
1882 	    }
1883 	    tracepoint(librbd, list_lockers_exit, r);
1884 	    return r;
1885 	  }
1886 	
1887 	  int Image::lock_exclusive(const string& cookie)
1888 	  {
1889 	    ImageCtx *ictx = (ImageCtx *)ctx;
1890 	    tracepoint(librbd, lock_exclusive_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie.c_str());
1891 	    int r = librbd::lock(ictx, true, cookie, "");
1892 	    tracepoint(librbd, lock_exclusive_exit, r);
1893 	    return r;
1894 	  }
1895 	
1896 	  int Image::lock_shared(const string& cookie, const std::string& tag)
1897 	  {
1898 	    ImageCtx *ictx = (ImageCtx *)ctx;
1899 	    tracepoint(librbd, lock_shared_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie.c_str(), tag.c_str());
1900 	    int r = librbd::lock(ictx, false, cookie, tag);
1901 	    tracepoint(librbd, lock_shared_exit, r);
1902 	    return r;
1903 	  }
1904 	
1905 	  int Image::unlock(const string& cookie)
1906 	  {
1907 	    ImageCtx *ictx = (ImageCtx *)ctx;
1908 	    tracepoint(librbd, unlock_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie.c_str());
1909 	    int r = librbd::unlock(ictx, cookie);
1910 	    tracepoint(librbd, unlock_exit, r);
1911 	    return r;
1912 	  }
1913 	
1914 	  int Image::break_lock(const string& client, const string& cookie)
1915 	  {
1916 	    ImageCtx *ictx = (ImageCtx *)ctx;
1917 	    tracepoint(librbd, break_lock_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, client.c_str(), cookie.c_str());
1918 	    int r = librbd::break_lock(ictx, client, cookie);
1919 	    tracepoint(librbd, break_lock_exit, r);
1920 	    return r;
1921 	  }
1922 	
1923 	  int Image::snap_create(const char *snap_name)
1924 	  {
1925 	    ImageCtx *ictx = (ImageCtx *)ctx;
1926 	    tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1927 	    int r = ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
1928 						  snap_name);
1929 	    tracepoint(librbd, snap_create_exit, r);
1930 	    return r;
1931 	  }
1932 	
1933 	  int Image::snap_remove(const char *snap_name)
1934 	  {
1935 	    ImageCtx *ictx = (ImageCtx *)ctx;
1936 	    tracepoint(librbd, snap_remove_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1937 	    librbd::NoOpProgressContext prog_ctx;
1938 	    int r = librbd::snap_remove(ictx, snap_name, 0, prog_ctx);
1939 	    tracepoint(librbd, snap_remove_exit, r);
1940 	    return r;
1941 	  }
1942 	
1943 	  int Image::snap_remove2(const char *snap_name, uint32_t flags, ProgressContext& pctx)
1944 	  {
1945 	    ImageCtx *ictx = (ImageCtx *)ctx;
1946 	    tracepoint(librbd, snap_remove2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name, flags);
1947 	    int r = librbd::snap_remove(ictx, snap_name, flags, pctx);
1948 	    tracepoint(librbd, snap_remove_exit, r);
1949 	    return r;
1950 	  }
1951 	
1952 	  int Image::snap_remove_by_id(uint64_t snap_id)
1953 	  {
1954 	    ImageCtx *ictx = (ImageCtx *)ctx;
1955 	    return librbd::api::Snapshot<>::remove(ictx, snap_id);
1956 	  }
1957 	
1958 	  int Image::snap_rollback(const char *snap_name)
1959 	  {
1960 	    ImageCtx *ictx = (ImageCtx *)ctx;
1961 	    tracepoint(librbd, snap_rollback_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1962 	    librbd::NoOpProgressContext prog_ctx;
1963 	    int r = ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(), snap_name, prog_ctx);
1964 	    tracepoint(librbd, snap_rollback_exit, r);
1965 	    return r;
1966 	  }
1967 	
1968 	  int Image::snap_rename(const char *srcname, const char *dstname)
1969 	  {
1970 	    ImageCtx *ictx = (ImageCtx *)ctx;
1971 	    tracepoint(librbd, snap_rename_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, srcname, dstname);
1972 	    int r = ictx->operations->snap_rename(srcname, dstname);
1973 	    tracepoint(librbd, snap_rename_exit, r);
1974 	    return r;
1975 	  }
1976 	
1977 	  int Image::snap_rollback_with_progress(const char *snap_name,
1978 						 ProgressContext& prog_ctx)
1979 	  {
1980 	    ImageCtx *ictx = (ImageCtx *)ctx;
1981 	    tracepoint(librbd, snap_rollback_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1982 	    int r = ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(), snap_name, prog_ctx);
1983 	    tracepoint(librbd, snap_rollback_exit, r);
1984 	    return r;
1985 	  }
1986 	
1987 	  int Image::snap_protect(const char *snap_name)
1988 	  {
1989 	    ImageCtx *ictx = (ImageCtx *)ctx;
1990 	    tracepoint(librbd, snap_protect_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1991 	    int r = ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(), snap_name);
1992 	    tracepoint(librbd, snap_protect_exit, r);
1993 	    return r;
1994 	  }
1995 	
1996 	  int Image::snap_unprotect(const char *snap_name)
1997 	  {
1998 	    ImageCtx *ictx = (ImageCtx *)ctx;
1999 	    tracepoint(librbd, snap_unprotect_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
2000 	    int r = ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(), snap_name);
2001 	    tracepoint(librbd, snap_unprotect_exit, r);
2002 	    return r;
2003 	  }
2004 	
2005 	  int Image::snap_is_protected(const char *snap_name, bool *is_protected)
2006 	  {
2007 	    ImageCtx *ictx = (ImageCtx *)ctx;
2008 	    tracepoint(librbd, snap_is_protected_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
2009 	    int r = librbd::snap_is_protected(ictx, snap_name, is_protected);
2010 	    tracepoint(librbd, snap_is_protected_exit, r, *is_protected ? 1 : 0);
2011 	    return r;
2012 	  }
2013 	
2014 	  int Image::snap_list(vector<librbd::snap_info_t>& snaps)
2015 	  {
2016 	    ImageCtx *ictx = (ImageCtx *)ctx;
2017 	    tracepoint(librbd, snap_list_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, &snaps);
2018 	    int r = librbd::snap_list(ictx, snaps);
2019 	    if (r >= 0) {
2020 	      for (int i = 0, n = snaps.size(); i < n; i++) {
2021 		tracepoint(librbd, snap_list_entry, snaps[i].id, snaps[i].size, snaps[i].name.c_str());
2022 	      }
2023 	    }
2024 	    tracepoint(librbd, snap_list_exit, r, snaps.size());
2025 	    if (r >= 0) {
2026 	      // A little ugly, but the C++ API doesn't need a Image::snap_list_end,
2027 	      // and we want the tracepoints to mirror the C API
2028 	      tracepoint(librbd, snap_list_end_enter, &snaps);
2029 	      tracepoint(librbd, snap_list_end_exit);
2030 	    }
2031 	    return r;
2032 	  }
2033 	
2034 	  bool Image::snap_exists(const char *snap_name)
2035 	  {
2036 	    ImageCtx *ictx = (ImageCtx *)ctx;
2037 	    tracepoint(librbd, snap_exists_enter, ictx, ictx->name.c_str(), 
2038 	      ictx->snap_name.c_str(), ictx->read_only, snap_name);
2039 	    bool exists; 
2040 	    int r = librbd::snap_exists(ictx, cls::rbd::UserSnapshotNamespace(), snap_name, &exists);
2041 	    tracepoint(librbd, snap_exists_exit, r, exists);
2042 	    if (r < 0) {
2043 	      // lie to caller since we don't know the real answer yet.
2044 	      return false;
2045 	    }
2046 	    return exists;
2047 	  }
2048 	
2049 	  // A safer verion of snap_exists.
2050 	  int Image::snap_exists2(const char *snap_name, bool *exists)
2051 	  {
2052 	    ImageCtx *ictx = (ImageCtx *)ctx;
2053 	    tracepoint(librbd, snap_exists_enter, ictx, ictx->name.c_str(), 
2054 	      ictx->snap_name.c_str(), ictx->read_only, snap_name);
2055 	    int r = librbd::snap_exists(ictx, cls::rbd::UserSnapshotNamespace(), snap_name, exists);
2056 	    tracepoint(librbd, snap_exists_exit, r, *exists);
2057 	    return r;
2058 	  }
2059 	
2060 	  int Image::snap_get_timestamp(uint64_t snap_id, struct timespec *timestamp)
2061 	  {
2062 	    ImageCtx *ictx = (ImageCtx *)ctx;
2063 	    tracepoint(librbd, snap_get_timestamp_enter, ictx, ictx->name.c_str());
2064 	    int r = librbd::snap_get_timestamp(ictx, snap_id, timestamp);
2065 	    tracepoint(librbd, snap_get_timestamp_exit, r);
2066 	    return r;
2067 	  }
2068 	
2069 	  int Image::snap_get_limit(uint64_t *limit)
2070 	  {
2071 	    ImageCtx *ictx = (ImageCtx *)ctx;
2072 	    tracepoint(librbd, snap_get_limit_enter, ictx, ictx->name.c_str());
2073 	    int r = librbd::snap_get_limit(ictx, limit);
2074 	    tracepoint(librbd, snap_get_limit_exit, r, *limit);
2075 	    return r;
2076 	  }
2077 	
2078 	  int Image::snap_get_namespace_type(uint64_t snap_id,
2079 					     snap_namespace_type_t *namespace_type) {
2080 	    ImageCtx *ictx = (ImageCtx *)ctx;
2081 	    tracepoint(librbd, snap_get_namespace_type_enter, ictx, ictx->name.c_str());
2082 	    int r = librbd::api::Snapshot<>::get_namespace_type(ictx, snap_id, namespace_type);
2083 	    tracepoint(librbd, snap_get_namespace_type_exit, r);
2084 	    return r;
2085 	  }
2086 	
2087 	  int Image::snap_get_group_namespace(uint64_t snap_id,
2088 				              snap_group_namespace_t *group_snap,
2089 	                                      size_t group_snap_size) {
2090 	    ImageCtx *ictx = (ImageCtx *)ctx;
2091 	    tracepoint(librbd, snap_get_group_namespace_enter, ictx,
2092 	               ictx->name.c_str());
2093 	
2094 	    if (group_snap_size != sizeof(snap_group_namespace_t)) {
2095 	      tracepoint(librbd, snap_get_group_namespace_exit, -ERANGE);
2096 	      return -ERANGE;
2097 	    }
2098 	
2099 	    int r = librbd::api::Snapshot<>::get_group_namespace(ictx, snap_id,
2100 	                                                         group_snap);
2101 	    tracepoint(librbd, snap_get_group_namespace_exit, r);
2102 	    return r;
2103 	  }
2104 	
2105 	  int Image::snap_get_trash_namespace(uint64_t snap_id,
2106 	                                      std::string* original_name) {
2107 	    ImageCtx *ictx = (ImageCtx *)ctx;
2108 	    return librbd::api::Snapshot<>::get_trash_namespace(ictx, snap_id,
2109 	                                                        original_name);
2110 	  }
2111 	
2112 	  int Image::snap_set_limit(uint64_t limit)
2113 	  {
2114 	    ImageCtx *ictx = (ImageCtx *)ctx;
2115 	
2116 	    tracepoint(librbd, snap_set_limit_enter, ictx, ictx->name.c_str(), limit);
2117 	    int r = ictx->operations->snap_set_limit(limit);
2118 	    tracepoint(librbd, snap_set_limit_exit, r);
2119 	    return r;
2120 	  }
2121 	
2122 	  int Image::snap_set(const char *snap_name)
2123 	  {
2124 	    ImageCtx *ictx = (ImageCtx *)ctx;
2125 	    tracepoint(librbd, snap_set_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
2126 	    int r = librbd::api::Image<>::snap_set(
2127 	      ictx, cls::rbd::UserSnapshotNamespace(), snap_name);
2128 	    tracepoint(librbd, snap_set_exit, r);
2129 	    return r;
2130 	  }
2131 	
2132 	  int Image::snap_set_by_id(uint64_t snap_id)
2133 	  {
2134 	    ImageCtx *ictx = (ImageCtx *)ctx;
2135 	    return librbd::api::Image<>::snap_set(ictx, snap_id);
2136 	  }
2137 	
2138 	  ssize_t Image::read(uint64_t ofs, size_t len, bufferlist& bl)
2139 	  {
2140 	    ImageCtx *ictx = (ImageCtx *)ctx;
2141 	    tracepoint(librbd, read_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
2142 	    bufferptr ptr(len);
2143 	    bl.push_back(std::move(ptr));
2144 	    
2145 	    int r = ictx->io_work_queue->read(ofs, len, io::ReadResult{&bl}, 0);
2146 	    tracepoint(librbd, read_exit, r);
2147 	    return r;
2148 	  }
2149 	
2150 	  ssize_t Image::read2(uint64_t ofs, size_t len, bufferlist& bl, int op_flags)
2151 	  {
2152 	    ImageCtx *ictx = (ImageCtx *)ctx;
2153 	    tracepoint(librbd, read2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
2154 			ictx->read_only, ofs, len, op_flags);
2155 	    bufferptr ptr(len);
2156 	    bl.push_back(std::move(ptr));
2157 	    
2158 	    int r = ictx->io_work_queue->read(ofs, len, io::ReadResult{&bl}, op_flags);
2159 	    tracepoint(librbd, read_exit, r);
2160 	    return r;
2161 	  }
2162 	
2163 	  int64_t Image::read_iterate(uint64_t ofs, size_t len,
2164 				      int (*cb)(uint64_t, size_t, const char *, void *),
2165 				      void *arg)
2166 	  {
2167 	    ImageCtx *ictx = (ImageCtx *)ctx;
2168 	    tracepoint(librbd, read_iterate_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
2169 	    
2170 	    int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg);
2171 	    tracepoint(librbd, read_iterate_exit, r);
2172 	    return r;
2173 	  }
2174 	
2175 	  int Image::read_iterate2(uint64_t ofs, uint64_t len,
2176 				      int (*cb)(uint64_t, size_t, const char *, void *),
2177 				      void *arg)
2178 	  {
2179 	    ImageCtx *ictx = (ImageCtx *)ctx;
2180 	    tracepoint(librbd, read_iterate2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
2181 	    
2182 	    int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg);
2183 	    if (r > 0)
2184 	      r = 0;
2185 	    tracepoint(librbd, read_iterate2_exit, r);
2186 	    return (int)r;
2187 	  }
2188 	
2189 	  int Image::diff_iterate(const char *fromsnapname,
2190 				  uint64_t ofs, uint64_t len,
2191 				  int (*cb)(uint64_t, size_t, int, void *),
2192 				  void *arg)
2193 	  {
2194 	    ImageCtx *ictx = (ImageCtx *)ctx;
2195 	    tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(),
2196 	               ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len,
2197 	               true, false);
2198 	    int r = librbd::api::DiffIterate<>::diff_iterate(ictx,
2199 							     cls::rbd::UserSnapshotNamespace(),
2200 							     fromsnapname, ofs,
2201 	                                                     len, true, false, cb, arg);
2202 	    tracepoint(librbd, diff_iterate_exit, r);
2203 	    return r;
2204 	  }
2205 	
2206 	  int Image::diff_iterate2(const char *fromsnapname, uint64_t ofs, uint64_t len,
2207 	                           bool include_parent, bool whole_object,
2208 	                           int (*cb)(uint64_t, size_t, int, void *), void *arg)
2209 	  {
2210 	    ImageCtx *ictx = (ImageCtx *)ctx;
2211 	    tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(),
2212 	              ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len,
2213 	              include_parent, whole_object);
2214 	    int r = librbd::api::DiffIterate<>::diff_iterate(ictx,
2215 							     cls::rbd::UserSnapshotNamespace(),
2216 							     fromsnapname, ofs,
2217 	                                                     len, include_parent,
2218 	                                                     whole_object, cb, arg);
2219 	    tracepoint(librbd, diff_iterate_exit, r);
2220 	    return r;
2221 	  }
2222 	
2223 	  ssize_t Image::write(uint64_t ofs, size_t len, bufferlist& bl)
2224 	  {
2225 	    ImageCtx *ictx = (ImageCtx *)ctx;
2226 	    tracepoint(librbd, write_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len, bl.length() < len ? NULL : bl.c_str());
2227 	    if (bl.length() < len) {
2228 	      tracepoint(librbd, write_exit, -EINVAL);
2229 	      return -EINVAL;
2230 	    }
2231 	
2232 	    int r = ictx->io_work_queue->write(ofs, len, bufferlist{bl}, 0);
2233 	    tracepoint(librbd, write_exit, r);
2234 	    return r;
2235 	  }
2236 	
2237 	   ssize_t Image::write2(uint64_t ofs, size_t len, bufferlist& bl, int op_flags)
2238 	  {
2239 	    ImageCtx *ictx = (ImageCtx *)ctx;
2240 	    tracepoint(librbd, write2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only,
2241 			ofs, len, bl.length() < len ? NULL : bl.c_str(), op_flags);
2242 	    if (bl.length() < len) {
2243 	      tracepoint(librbd, write_exit, -EINVAL);
2244 	      return -EINVAL;
2245 	    }
2246 	
2247 	    int r = ictx->io_work_queue->write(ofs, len, bufferlist{bl}, op_flags);
2248 	    tracepoint(librbd, write_exit, r);
2249 	    return r;
2250 	  }
2251 	
2252 	  int Image::discard(uint64_t ofs, uint64_t len)
2253 	  {
2254 	    ImageCtx *ictx = (ImageCtx *)ctx;
2255 	    tracepoint(librbd, discard_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
2256 	    if (len > static_cast<uint64_t>(std::numeric_limits<int32_t>::max())) {
2257 	        tracepoint(librbd, discard_exit, -EINVAL);
2258 	        return -EINVAL;
2259 	    }
2260 	    int r = ictx->io_work_queue->discard(
2261 	      ofs, len, ictx->discard_granularity_bytes);
2262 	    tracepoint(librbd, discard_exit, r);
2263 	    return r;
2264 	  }
2265 	
2266 	  ssize_t Image::writesame(uint64_t ofs, size_t len, bufferlist& bl, int op_flags)
2267 	  {
2268 	    ImageCtx *ictx = (ImageCtx *)ctx;
2269 	    tracepoint(librbd, writesame_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
2270 	               ictx->read_only, ofs, len, bl.length() <= 0 ? NULL : bl.c_str(), bl.length(),
2271 	               op_flags);
2272 	    if (bl.length() <= 0 || len % bl.length() ||
2273 	        len > static_cast<size_t>(std::numeric_limits<int>::max())) {
2274 	      tracepoint(librbd, writesame_exit, -EINVAL);
2275 	      return -EINVAL;
2276 	    }
2277 	
2278 	    bool discard_zero = ictx->config.get_val<bool>("rbd_discard_on_zeroed_write_same");
2279 	    if (discard_zero && mem_is_zero(bl.c_str(), bl.length())) {
2280 	      int r = ictx->io_work_queue->discard(ofs, len, 0);
2281 	      tracepoint(librbd, writesame_exit, r);
2282 	      return r;
2283 	    }
2284 	
2285 	    int r = ictx->io_work_queue->writesame(ofs, len, bufferlist{bl}, op_flags);
2286 	    tracepoint(librbd, writesame_exit, r);
2287 	    return r;
2288 	  }
2289 	
2290 	  ssize_t Image::compare_and_write(uint64_t ofs, size_t len,
2291 	                                   ceph::bufferlist &cmp_bl, ceph::bufferlist& bl,
2292 	                                   uint64_t *mismatch_off, int op_flags)
2293 	  {
2294 	    ImageCtx *ictx = (ImageCtx *)ctx;
2295 	    tracepoint(librbd, compare_and_write_enter, ictx, ictx->name.c_str(),
2296 	               ictx->snap_name.c_str(),
2297 	               ictx->read_only, ofs, len, cmp_bl.length() < len ? NULL : cmp_bl.c_str(),
2298 	               bl.length() < len ? NULL : bl.c_str(), op_flags);
2299 	
2300 	    if (bl.length() < len) {
2301 	      tracepoint(librbd, write_exit, -EINVAL);
2302 	      return -EINVAL;
2303 	    }
2304 	
2305 	    int r = ictx->io_work_queue->compare_and_write(ofs, len, bufferlist{cmp_bl},
2306 	                                                   bufferlist{bl}, mismatch_off,
2307 	                                                   op_flags);
2308 	
2309 	    tracepoint(librbd, compare_and_write_exit, r);
2310 	
2311 	    return r;
2312 	  }
2313 	
2314 	  int Image::aio_write(uint64_t off, size_t len, bufferlist& bl,
2315 			       RBD::AioCompletion *c)
2316 	  {
2317 	    ImageCtx *ictx = (ImageCtx *)ctx;
2318 	    tracepoint(librbd, aio_write_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, bl.length() < len ? NULL : bl.c_str(), c->pc);
2319 	    if (bl.length() < len) {
2320 	      tracepoint(librbd, aio_write_exit, -EINVAL);
2321 	      return -EINVAL;
2322 	    }
2323 	    ictx->io_work_queue->aio_write(get_aio_completion(c), off, len,
2324 	                                   bufferlist{bl}, 0);
2325 	
2326 	    tracepoint(librbd, aio_write_exit, 0);
2327 	    return 0;
2328 	  }
2329 	
2330 	  int Image::aio_write2(uint64_t off, size_t len, bufferlist& bl,
2331 				  RBD::AioCompletion *c, int op_flags)
2332 	  {
2333 	    ImageCtx *ictx = (ImageCtx *)ctx;
2334 	    tracepoint(librbd, aio_write2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
2335 			ictx->read_only, off, len, bl.length() < len ? NULL : bl.c_str(), c->pc, op_flags);
2336 	    if (bl.length() < len) {
2337 	      tracepoint(librbd, aio_write_exit, -EINVAL);
2338 	      return -EINVAL;
2339 	    }
2340 	    ictx->io_work_queue->aio_write(get_aio_completion(c), off, len,
2341 	                                   bufferlist{bl}, op_flags);
2342 	
2343 	    tracepoint(librbd, aio_write_exit, 0);
2344 	    return 0;
2345 	  }
2346 	
2347 	  int Image::aio_discard(uint64_t off, uint64_t len, RBD::AioCompletion *c)
2348 	  {
2349 	    ImageCtx *ictx = (ImageCtx *)ctx;
2350 	    tracepoint(librbd, aio_discard_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, c->pc);
2351 	    ictx->io_work_queue->aio_discard(
2352 	      get_aio_completion(c), off, len, ictx->discard_granularity_bytes);
2353 	    tracepoint(librbd, aio_discard_exit, 0);
2354 	    return 0;
2355 	  }
2356 	
2357 	  int Image::aio_read(uint64_t off, size_t len, bufferlist& bl,
2358 			      RBD::AioCompletion *c)
2359 	  {
2360 	    ImageCtx *ictx = (ImageCtx *)ctx;
2361 	    tracepoint(librbd, aio_read_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, bl.c_str(), c->pc);
2362 	    ldout(ictx->cct, 10) << "Image::aio_read() buf=" << (void *)bl.c_str() << "~"
2363 				 << (void *)(bl.c_str() + len - 1) << dendl;
2364 	
2365 	    ictx->io_work_queue->aio_read(get_aio_completion(c), off, len,
2366 	                                  io::ReadResult{&bl}, 0);
2367 	    tracepoint(librbd, aio_read_exit, 0);
2368 	    return 0;
2369 	  }
2370 	
2371 	  int Image::aio_read2(uint64_t off, size_t len, bufferlist& bl,
2372 				RBD::AioCompletion *c, int op_flags)
2373 	  {
2374 	    ImageCtx *ictx = (ImageCtx *)ctx;
2375 	    tracepoint(librbd, aio_read2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
2376 			ictx->read_only, off, len, bl.c_str(), c->pc, op_flags);
2377 	    ldout(ictx->cct, 10) << "Image::aio_read() buf=" << (void *)bl.c_str() << "~"
2378 				 << (void *)(bl.c_str() + len - 1) << dendl;
2379 	
2380 	    ictx->io_work_queue->aio_read(get_aio_completion(c), off, len,
2381 	                                  io::ReadResult{&bl}, op_flags);
2382 	    tracepoint(librbd, aio_read_exit, 0);
2383 	    return 0;
2384 	  }
2385 	
2386 	  int Image::flush()
2387 	  {
2388 	    ImageCtx *ictx = (ImageCtx *)ctx;
2389 	    tracepoint(librbd, flush_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2390 	    int r = ictx->io_work_queue->flush();
2391 	    tracepoint(librbd, flush_exit, r);
2392 	    return r;
2393 	  }
2394 	
2395 	  int Image::aio_flush(RBD::AioCompletion *c)
2396 	  {
2397 	    ImageCtx *ictx = (ImageCtx *)ctx;
2398 	    tracepoint(librbd, aio_flush_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, c->pc);
2399 	    ictx->io_work_queue->aio_flush(get_aio_completion(c));
2400 	    tracepoint(librbd, aio_flush_exit, 0);
2401 	    return 0;
2402 	  }
2403 	
2404 	  int Image::aio_writesame(uint64_t off, size_t len, bufferlist& bl,
2405 	                           RBD::AioCompletion *c, int op_flags)
2406 	  {
2407 	    ImageCtx *ictx = (ImageCtx *)ctx;
2408 	    tracepoint(librbd, aio_writesame_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
2409 	               ictx->read_only, off, len, bl.length() <= len ? NULL : bl.c_str(), bl.length(),
2410 	               c->pc, op_flags);
2411 	    if (bl.length() <= 0 || len % bl.length()) {
2412 	      tracepoint(librbd, aio_writesame_exit, -EINVAL);
2413 	      return -EINVAL;
2414 	    }
2415 	
2416 	    bool discard_zero = ictx->config.get_val<bool>("rbd_discard_on_zeroed_write_same");
2417 	    if (discard_zero && mem_is_zero(bl.c_str(), bl.length())) {
2418 	      ictx->io_work_queue->aio_discard(get_aio_completion(c), off, len, 0);
2419 	      tracepoint(librbd, aio_writesame_exit, 0);
2420 	      return 0;
2421 	    }
2422 	
2423 	    ictx->io_work_queue->aio_writesame(get_aio_completion(c), off, len,
2424 	                                       bufferlist{bl}, op_flags);
2425 	    tracepoint(librbd, aio_writesame_exit, 0);
2426 	    return 0;
2427 	  }
2428 	
2429 	  int Image::aio_compare_and_write(uint64_t off, size_t len,
2430 	                                   ceph::bufferlist& cmp_bl, ceph::bufferlist& bl,
2431 	                                   RBD::AioCompletion *c, uint64_t *mismatch_off,
2432 	                                   int op_flags)
2433 	  {
2434 	    ImageCtx *ictx = (ImageCtx *)ctx;
2435 	    tracepoint(librbd, aio_compare_and_write_enter, ictx, ictx->name.c_str(),
2436 	               ictx->snap_name.c_str(),
2437 	               ictx->read_only, off, len, cmp_bl.length() < len ? NULL : cmp_bl.c_str(),
2438 	               bl.length() < len ? NULL : bl.c_str(), c->pc, op_flags);
2439 	
2440 	    if (bl.length() < len) {
2441 	      tracepoint(librbd, compare_and_write_exit, -EINVAL);
2442 	      return -EINVAL;
2443 	    }
2444 	
2445 	    ictx->io_work_queue->aio_compare_and_write(get_aio_completion(c), off, len,
2446 	                                               bufferlist{cmp_bl}, bufferlist{bl},
2447 	                                               mismatch_off, op_flags, false);
2448 	
2449 	    tracepoint(librbd, aio_compare_and_write_exit, 0);
2450 	
2451 	    return 0;
2452 	  }
2453 	
2454 	  int Image::invalidate_cache()
2455 	  {
2456 	    ImageCtx *ictx = (ImageCtx *)ctx;
2457 	    tracepoint(librbd, invalidate_cache_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2458 	    int r = librbd::invalidate_cache(ictx);
2459 	    tracepoint(librbd, invalidate_cache_exit, r);
2460 	    return r;
2461 	  }
2462 	
2463 	  int Image::poll_io_events(RBD::AioCompletion **comps, int numcomp)
2464 	  {
2465 	    io::AioCompletion *cs[numcomp];
2466 	    ImageCtx *ictx = (ImageCtx *)ctx;
2467 	    tracepoint(librbd, poll_io_events_enter, ictx, numcomp);
2468 	    int r = librbd::poll_io_events(ictx, cs, numcomp);
2469 	    tracepoint(librbd, poll_io_events_exit, r);
2470 	    if (r > 0) {
2471 	      for (int i = 0; i < r; ++i)
2472 	        comps[i] = (RBD::AioCompletion *)cs[i]->rbd_comp;
2473 	    }
2474 	    return r;
2475 	  }
2476 	
2477 	  int Image::metadata_get(const std::string &key, std::string *value)
2478 	  {
2479 	    ImageCtx *ictx = (ImageCtx *)ctx;
2480 	    tracepoint(librbd, metadata_get_enter, ictx, key.c_str());
2481 	    int r = librbd::metadata_get(ictx, key, value);
2482 	    if (r < 0) {
2483 	      tracepoint(librbd, metadata_get_exit, r, key.c_str(), NULL);
2484 	    } else {
2485 	      tracepoint(librbd, metadata_get_exit, r, key.c_str(), value->c_str());
2486 	    }
2487 	    return r;
2488 	  }
2489 	
2490 	  int Image::metadata_set(const std::string &key, const std::string &value)
2491 	  {
2492 	    ImageCtx *ictx = (ImageCtx *)ctx;
2493 	    tracepoint(librbd, metadata_set_enter, ictx, key.c_str(), value.c_str());
2494 	    int r = ictx->operations->metadata_set(key, value);
2495 	    tracepoint(librbd, metadata_set_exit, r);
2496 	    return r;
2497 	  }
2498 	
2499 	  int Image::metadata_remove(const std::string &key)
2500 	  {
2501 	    ImageCtx *ictx = (ImageCtx *)ctx;
2502 	    tracepoint(librbd, metadata_remove_enter, ictx, key.c_str());
2503 	    int r = ictx->operations->metadata_remove(key);
2504 	    tracepoint(librbd, metadata_remove_exit, r);
2505 	    return r;
2506 	  }
2507 	
2508 	  int Image::metadata_list(const std::string &start, uint64_t max, map<string, bufferlist> *pairs)
2509 	  {
2510 	    ImageCtx *ictx = (ImageCtx *)ctx;
2511 	    tracepoint(librbd, metadata_list_enter, ictx);
2512 	    int r = librbd::metadata_list(ictx, start, max, pairs);
2513 	    if (r >= 0) {
2514 	      for (map<string, bufferlist>::iterator it = pairs->begin();
2515 	           it != pairs->end(); ++it) {
2516 	        tracepoint(librbd, metadata_list_entry, it->first.c_str(), it->second.c_str());
2517 	      }
2518 	    }
2519 	    tracepoint(librbd, metadata_list_exit, r);
2520 	    return r;
2521 	  }
2522 	
2523 	  int Image::mirror_image_enable() {
2524 	    ImageCtx *ictx = (ImageCtx *)ctx;
2525 	    return librbd::api::Mirror<>::image_enable(ictx, false);
2526 	  }
2527 	
2528 	  int Image::mirror_image_disable(bool force) {
2529 	    ImageCtx *ictx = (ImageCtx *)ctx;
2530 	    return librbd::api::Mirror<>::image_disable(ictx, force);
2531 	  }
2532 	
2533 	  int Image::mirror_image_promote(bool force) {
2534 	    ImageCtx *ictx = (ImageCtx *)ctx;
2535 	    return librbd::api::Mirror<>::image_promote(ictx, force);
2536 	  }
2537 	
2538 	  int Image::mirror_image_demote() {
2539 	    ImageCtx *ictx = (ImageCtx *)ctx;
2540 	    return librbd::api::Mirror<>::image_demote(ictx);
2541 	  }
2542 	
2543 	  int Image::mirror_image_resync()
2544 	  {
2545 	    ImageCtx *ictx = (ImageCtx *)ctx;
2546 	    return librbd::api::Mirror<>::image_resync(ictx);
2547 	  }
2548 	
2549 	  int Image::mirror_image_get_info(mirror_image_info_t *mirror_image_info,
2550 	                                   size_t info_size) {
2551 	    ImageCtx *ictx = (ImageCtx *)ctx;
2552 	
2553 	    if (sizeof(mirror_image_info_t) != info_size) {
2554 	      return -ERANGE;
2555 	    }
2556 	
2557 	    return librbd::api::Mirror<>::image_get_info(ictx, mirror_image_info);
2558 	  }
2559 	
2560 	  int Image::mirror_image_get_status(mirror_image_status_t *mirror_image_status,
2561 					     size_t status_size) {
2562 	    ImageCtx *ictx = (ImageCtx *)ctx;
2563 	
2564 	    if (sizeof(mirror_image_status_t) != status_size) {
2565 	      return -ERANGE;
2566 	    }
2567 	
2568 	    return librbd::api::Mirror<>::image_get_status(ictx, mirror_image_status);
2569 	  }
2570 	
2571 	  int Image::mirror_image_get_instance_id(std::string *instance_id) {
2572 	    ImageCtx *ictx = (ImageCtx *)ctx;
2573 	
2574 	    return librbd::api::Mirror<>::image_get_instance_id(ictx, instance_id);
2575 	  }
2576 	
2577 	  int Image::aio_mirror_image_promote(bool force, RBD::AioCompletion *c) {
2578 	    ImageCtx *ictx = (ImageCtx *)ctx;
2579 	    librbd::api::Mirror<>::image_promote(
2580 	      ictx, force, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
2581 	                                       get_aio_completion(c)));
2582 	    return 0;
2583 	  }
2584 	
2585 	  int Image::aio_mirror_image_demote(RBD::AioCompletion *c) {
2586 	    ImageCtx *ictx = (ImageCtx *)ctx;
2587 	    librbd::api::Mirror<>::image_demote(
2588 	      ictx, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
2589 	                                get_aio_completion(c)));
2590 	    return 0;
2591 	  }
2592 	
2593 	  int Image::aio_mirror_image_get_info(mirror_image_info_t *mirror_image_info,
2594 	                                       size_t info_size,
2595 	                                       RBD::AioCompletion *c) {
2596 	    ImageCtx *ictx = (ImageCtx *)ctx;
2597 	
2598 	    if (sizeof(mirror_image_info_t) != info_size) {
2599 	      return -ERANGE;
2600 	    }
2601 	
2602 	    librbd::api::Mirror<>::image_get_info(
2603 	      ictx, mirror_image_info,
2604 	      new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
2605 	                          get_aio_completion(c)));
2606 	    return 0;
2607 	  }
2608 	
2609 	  int Image::aio_mirror_image_get_status(mirror_image_status_t *status,
2610 	                                         size_t status_size,
2611 	                                         RBD::AioCompletion *c) {
2612 	    ImageCtx *ictx = (ImageCtx *)ctx;
2613 	
2614 	    if (sizeof(mirror_image_status_t) != status_size) {
2615 	      return -ERANGE;
2616 	    }
2617 	
2618 	    librbd::api::Mirror<>::image_get_status(
2619 	      ictx, status, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
2620 	                                        get_aio_completion(c)));
2621 	    return 0;
2622 	  }
2623 	
2624 	  int Image::update_watch(UpdateWatchCtx *wctx, uint64_t *handle) {
2625 	    ImageCtx *ictx = (ImageCtx *)ctx;
2626 	    tracepoint(librbd, update_watch_enter, ictx, wctx);
2627 	    int r = ictx->state->register_update_watcher(wctx, handle);
2628 	    tracepoint(librbd, update_watch_exit, r, *handle);
2629 	    return r;
2630 	  }
2631 	
2632 	  int Image::update_unwatch(uint64_t handle) {
2633 	    ImageCtx *ictx = (ImageCtx *)ctx;
2634 	    tracepoint(librbd, update_unwatch_enter, ictx, handle);
2635 	    int r = ictx->state->unregister_update_watcher(handle);
2636 	    tracepoint(librbd, update_unwatch_exit, r);
2637 	    return r;
2638 	  }
2639 	
2640 	  int Image::list_watchers(std::list<librbd::image_watcher_t> &watchers) {
2641 	    ImageCtx *ictx = (ImageCtx *)ctx;
2642 	    tracepoint(librbd, list_watchers_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2643 	    int r = librbd::list_watchers(ictx, watchers);
2644 	#ifdef WITH_LTTNG
2645 	    if (r >= 0) {
2646 	      for (auto &watcher : watchers) {
2647 		tracepoint(librbd, list_watchers_entry, watcher.addr.c_str(), watcher.id, watcher.cookie);
2648 	      }
2649 	    }
2650 	#endif
2651 	    tracepoint(librbd, list_watchers_exit, r, watchers.size());
2652 	    return r;
2653 	  }
2654 	
2655 	  int Image::config_list(std::vector<config_option_t> *options) {
2656 	    ImageCtx *ictx = (ImageCtx *)ctx;
2657 	    return librbd::api::Config<>::list(ictx, options);
2658 	  }
2659 	
2660 	} // namespace librbd
2661 	
2662 	extern "C" void rbd_version(int *major, int *minor, int *extra)
2663 	{
2664 	  if (major)
2665 	    *major = LIBRBD_VER_MAJOR;
2666 	  if (minor)
2667 	    *minor = LIBRBD_VER_MINOR;
2668 	  if (extra)
2669 	    *extra = LIBRBD_VER_EXTRA;
2670 	}
2671 	
2672 	extern "C" void rbd_image_options_create(rbd_image_options_t* opts)
2673 	{
2674 	  librbd::image_options_create(opts);
2675 	}
2676 	
2677 	extern "C" void rbd_image_options_destroy(rbd_image_options_t opts)
2678 	{
2679 	  librbd::image_options_destroy(opts);
2680 	}
2681 	
2682 	extern "C" int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
2683 						    const char* optval)
2684 	{
2685 	  return librbd::image_options_set(opts, optname, optval);
2686 	}
2687 	
2688 	extern "C" int rbd_image_options_set_uint64(rbd_image_options_t opts, int optname,
2689 						    uint64_t optval)
2690 	{
2691 	  return librbd::image_options_set(opts, optname, optval);
2692 	}
2693 	
2694 	extern "C" int rbd_image_options_get_string(rbd_image_options_t opts, int optname,
2695 						    char* optval, size_t maxlen)
2696 	{
2697 	  std::string optval_;
2698 	
2699 	  int r = librbd::image_options_get(opts, optname, &optval_);
2700 	
2701 	  if (r < 0) {
2702 	    return r;
2703 	  }
2704 	
2705 	  if (optval_.size() >= maxlen) {
2706 	    return -E2BIG;
2707 	  }
2708 	
2709 	  strncpy(optval, optval_.c_str(), maxlen);
2710 	
2711 	  return 0;
2712 	}
2713 	
2714 	extern "C" int rbd_image_options_get_uint64(rbd_image_options_t opts, int optname,
2715 					 uint64_t* optval)
2716 	{
2717 	  return librbd::image_options_get(opts, optname, optval);
2718 	}
2719 	
2720 	extern "C" int rbd_image_options_is_set(rbd_image_options_t opts, int optname,
2721 	                                        bool* is_set)
2722 	{
2723 	  return librbd::image_options_is_set(opts, optname, is_set);
2724 	}
2725 	
2726 	extern "C" int rbd_image_options_unset(rbd_image_options_t opts, int optname)
2727 	{
2728 	  return librbd::image_options_unset(opts, optname);
2729 	}
2730 	
2731 	extern "C" void rbd_image_options_clear(rbd_image_options_t opts)
2732 	{
2733 	  librbd::image_options_clear(opts);
2734 	}
2735 	
2736 	extern "C" int rbd_image_options_is_empty(rbd_image_options_t opts)
2737 	{
2738 	  return librbd::image_options_is_empty(opts);
2739 	}
2740 	
2741 	/* pool mirroring */
2742 	extern "C" int rbd_mirror_site_name_get(rados_t cluster, char *name,
2743 	                                        size_t *max_len) {
2744 	  librados::Rados rados;
2745 	  librados::Rados::from_rados_t(cluster, rados);
2746 	
2747 	  std::string site_name;
2748 	  int r = librbd::api::Mirror<>::site_name_get(rados, &site_name);
2749 	  if (r < 0) {
2750 	    return r;
2751 	  }
2752 	
2753 	  auto total_len = site_name.size() + 1;
2754 	  if (*max_len < total_len) {
2755 	    *max_len = total_len;
2756 	    return -ERANGE;
2757 	  }
2758 	  *max_len = total_len;
2759 	
2760 	  strcpy(name, site_name.c_str());
2761 	  return 0;
2762 	}
2763 	
2764 	extern "C" int rbd_mirror_site_name_set(rados_t cluster, const char *name) {
2765 	  librados::Rados rados;
2766 	  librados::Rados::from_rados_t(cluster, rados);
2767 	  return librbd::api::Mirror<>::site_name_set(rados, name);
2768 	}
2769 	
2770 	extern "C" int rbd_mirror_mode_get(rados_ioctx_t p,
2771 	                                   rbd_mirror_mode_t *mirror_mode) {
2772 	  librados::IoCtx io_ctx;
2773 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2774 	  return librbd::api::Mirror<>::mode_get(io_ctx, mirror_mode);
2775 	}
2776 	
2777 	extern "C" int rbd_mirror_mode_set(rados_ioctx_t p,
2778 	                                   rbd_mirror_mode_t mirror_mode) {
2779 	  librados::IoCtx io_ctx;
2780 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2781 	  return librbd::api::Mirror<>::mode_set(io_ctx, mirror_mode);
2782 	}
2783 	
2784 	extern "C" int rbd_mirror_peer_bootstrap_create(rados_ioctx_t p, char *token,
2785 	                                                size_t *max_len) {
2786 	  librados::IoCtx io_ctx;
2787 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2788 	
2789 	  std::string token_str;
2790 	  int r = librbd::api::Mirror<>::peer_bootstrap_create(io_ctx, &token_str);
2791 	  if (r < 0) {
2792 	    return r;
2793 	  }
2794 	
2795 	  auto total_len = token_str.size() + 1;
2796 	  if (*max_len < total_len) {
2797 	    *max_len = total_len;
2798 	    return -ERANGE;
2799 	  }
2800 	  *max_len = total_len;
2801 	
2802 	  strcpy(token, token_str.c_str());
2803 	  return 0;
2804 	}
2805 	
2806 	extern "C" int rbd_mirror_peer_bootstrap_import(
2807 	    rados_ioctx_t p, rbd_mirror_peer_direction_t direction,
2808 	    const char *token) {
2809 	  librados::IoCtx io_ctx;
2810 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2811 	
2812 	  return librbd::api::Mirror<>::peer_bootstrap_import(io_ctx, direction, token);
2813 	}
2814 	
2815 	extern "C" int rbd_mirror_peer_add(rados_ioctx_t p, char *uuid,
2816 	                                   size_t uuid_max_length,
2817 	                                   const char *cluster_name,
2818 	                                   const char *client_name) {
2819 	  static const std::size_t UUID_LENGTH = 36;
2820 	
2821 	  librados::IoCtx io_ctx;
2822 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2823 	
2824 	  if (uuid_max_length < UUID_LENGTH + 1) {
2825 	    return -E2BIG;
2826 	  }
2827 	
2828 	  std::string uuid_str;
2829 	  int r = librbd::api::Mirror<>::peer_add(io_ctx, &uuid_str, cluster_name,
2830 	                                          client_name);
2831 	  if (r >= 0) {
2832 	    strncpy(uuid, uuid_str.c_str(), uuid_max_length);
2833 	    uuid[uuid_max_length - 1] = '\0';
2834 	  }
2835 	  return r;
2836 	}
2837 	
2838 	extern "C" int rbd_mirror_peer_remove(rados_ioctx_t p, const char *uuid) {
2839 	  librados::IoCtx io_ctx;
2840 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2841 	  int r = librbd::api::Mirror<>::peer_remove(io_ctx, uuid);
2842 	  return r;
2843 	}
2844 	
2845 	extern "C" int rbd_mirror_peer_list(rados_ioctx_t p,
2846 	                                    rbd_mirror_peer_t *peers, int *max_peers) {
2847 	  librados::IoCtx io_ctx;
2848 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2849 	
2850 	  std::vector<librbd::mirror_peer_t> peer_vector;
2851 	  int r = librbd::api::Mirror<>::peer_list(io_ctx, &peer_vector);
2852 	  if (r < 0) {
2853 	    return r;
2854 	  }
2855 	
2856 	  if (*max_peers < static_cast<int>(peer_vector.size())) {
2857 	    *max_peers = static_cast<int>(peer_vector.size());
2858 	    return -ERANGE;
2859 	  }
2860 	
2861 	  for (int i = 0; i < static_cast<int>(peer_vector.size()); ++i) {
2862 	    peers[i].uuid = strdup(peer_vector[i].uuid.c_str());
2863 	    peers[i].cluster_name = strdup(peer_vector[i].cluster_name.c_str());
2864 	    peers[i].client_name = strdup(peer_vector[i].client_name.c_str());
2865 	  }
2866 	  *max_peers = static_cast<int>(peer_vector.size());
2867 	  return 0;
2868 	}
2869 	
2870 	extern "C" void rbd_mirror_peer_list_cleanup(rbd_mirror_peer_t *peers,
2871 	                                             int max_peers) {
2872 	  for (int i = 0; i < max_peers; ++i) {
2873 	    free(peers[i].uuid);
2874 	    free(peers[i].cluster_name);
2875 	    free(peers[i].client_name);
2876 	  }
2877 	}
2878 	
2879 	extern "C" int rbd_mirror_peer_set_client(rados_ioctx_t p, const char *uuid,
2880 	                                          const char *client_name) {
2881 	  librados::IoCtx io_ctx;
2882 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2883 	  return librbd::api::Mirror<>::peer_set_client(io_ctx, uuid, client_name);
2884 	}
2885 	
2886 	extern "C" int rbd_mirror_peer_set_cluster(rados_ioctx_t p, const char *uuid,
2887 	                                           const char *cluster_name) {
2888 	  librados::IoCtx io_ctx;
2889 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2890 	  return librbd::api::Mirror<>::peer_set_cluster(io_ctx, uuid, cluster_name);
2891 	}
2892 	
2893 	extern "C" int rbd_mirror_peer_get_attributes(
2894 	    rados_ioctx_t p, const char *uuid, char *keys, size_t *max_key_len,
2895 	    char *values, size_t *max_val_len, size_t *key_value_count) {
2896 	  librados::IoCtx io_ctx;
2897 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2898 	
2899 	  std::map<std::string, std::string> attributes;
2900 	  int r = librbd::api::Mirror<>::peer_get_attributes(io_ctx, uuid, &attributes);
2901 	  if (r < 0) {
2902 	    return r;
2903 	  }
2904 	
2905 	  size_t key_total_len = 0, val_total_len = 0;
2906 	  for (auto& it : attributes) {
2907 	    key_total_len += it.first.size() + 1;
2908 	    val_total_len += it.second.length() + 1;
2909 	  }
2910 	
2911 	  bool too_short = ((*max_key_len < key_total_len) ||
2912 	                    (*max_val_len < val_total_len));
2913 	
2914 	  *max_key_len = key_total_len;
2915 	  *max_val_len = val_total_len;
2916 	  *key_value_count = attributes.size();
2917 	  if (too_short) {
2918 	    return -ERANGE;
2919 	  }
2920 	
2921 	  char *keys_p = keys;
2922 	  char *values_p = values;
2923 	  for (auto& it : attributes) {
2924 	    strncpy(keys_p, it.first.c_str(), it.first.size() + 1);
2925 	    keys_p += it.first.size() + 1;
2926 	
2927 	    strncpy(values_p, it.second.c_str(), it.second.length() + 1);
2928 	    values_p += it.second.length() + 1;
2929 	  }
2930 	
2931 	  return 0;
2932 	}
2933 	
2934 	extern "C" int rbd_mirror_peer_set_attributes(
2935 	    rados_ioctx_t p, const char *uuid, const char *keys, const char *values,
2936 	    size_t count) {
2937 	  librados::IoCtx io_ctx;
2938 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2939 	
2940 	  std::map<std::string, std::string> attributes;
2941 	
2942 	  for (size_t i = 0; i < count; ++i) {
2943 	    const char* key = keys;
2944 	    keys += strlen(key) + 1;
2945 	    const char* value = values;
2946 	    values += strlen(value) + 1;
2947 	    attributes[key] = value;
2948 	  }
2949 	
2950 	  return librbd::api::Mirror<>::peer_set_attributes(io_ctx, uuid, attributes);
2951 	}
2952 	
2953 	extern "C" int rbd_mirror_image_status_list(rados_ioctx_t p,
2954 	    const char *start_id, size_t max, char **image_ids,
2955 	    rbd_mirror_image_status_t *images, size_t *len) {
2956 	  librados::IoCtx io_ctx;
2957 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2958 	  std::map<std::string, librbd::mirror_image_status_t> cpp_images;
2959 	
2960 	  int r = librbd::api::Mirror<>::image_status_list(io_ctx, start_id, max,
2961 	                                                   &cpp_images);
2962 	  if (r < 0) {
2963 	    return r;
2964 	  }
2965 	
2966 	  size_t i = 0;
2967 	  for (auto &it : cpp_images) {
2968 	    ceph_assert(i < max);
2969 	    const std::string &image_id = it.first;
2970 	    image_ids[i] = strdup(image_id.c_str());
2971 	    mirror_image_status_cpp_to_c(it.second, &images[i]);
2972 	    i++;
2973 	  }
2974 	  *len = i;
2975 	  return 0;
2976 	}
2977 	
2978 	extern "C" void rbd_mirror_image_status_list_cleanup(char **image_ids,
2979 	    rbd_mirror_image_status_t *images, size_t len) {
2980 	  for (size_t i = 0; i < len; i++) {
2981 	    free(image_ids[i]);
2982 	    free(images[i].name);
2983 	    free(images[i].info.global_id);
2984 	    free(images[i].description);
2985 	  }
2986 	}
2987 	
2988 	extern "C" int rbd_mirror_image_status_summary(rados_ioctx_t p,
2989 	    rbd_mirror_image_status_state_t *states, int *counts, size_t *maxlen) {
2990 	
2991 	  librados::IoCtx io_ctx;
2992 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2993 	
2994 	  std::map<librbd::mirror_image_status_state_t, int> states_;
2995 	  int r = librbd::api::Mirror<>::image_status_summary(io_ctx, &states_);
2996 	  if (r < 0) {
2997 	    return r;
2998 	  }
2999 	
3000 	  size_t i = 0;
3001 	  for (auto &it : states_) {
3002 	    if (i == *maxlen) {
3003 	      return -ERANGE;
3004 	    }
3005 	    states[i] = it.first;
3006 	    counts[i] = it.second;
3007 	    i++;
3008 	  }
3009 	  *maxlen = i;
3010 	  return 0;
3011 	}
3012 	
3013 	extern "C" int rbd_mirror_image_instance_id_list(
3014 	    rados_ioctx_t p, const char *start_id, size_t max, char **image_ids,
3015 	    char **instance_ids, size_t *len) {
3016 	  librados::IoCtx io_ctx;
3017 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3018 	  std::map<std::string, std::string> cpp_instance_ids;
3019 	
3020 	  int r = librbd::api::Mirror<>::image_instance_id_list(io_ctx, start_id, max,
3021 	                                                        &cpp_instance_ids);
3022 	  if (r < 0) {
3023 	    return r;
3024 	  }
3025 	
3026 	  size_t i = 0;
3027 	  for (auto &it : cpp_instance_ids) {
3028 	    ceph_assert(i < max);
3029 	    image_ids[i] = strdup(it.first.c_str());
3030 	    instance_ids[i] = strdup(it.second.c_str());
3031 	    i++;
3032 	  }
3033 	  *len = i;
3034 	  return 0;
3035 	}
3036 	
3037 	extern "C" void rbd_mirror_image_instance_id_list_cleanup(
3038 	    char **image_ids, char **instance_ids, size_t len) {
3039 	  for (size_t i = 0; i < len; i++) {
3040 	    free(image_ids[i]);
3041 	    free(instance_ids[i]);
3042 	  }
3043 	}
3044 	
3045 	/* helpers */
3046 	
3047 	extern "C" void rbd_image_spec_cleanup(rbd_image_spec_t *image)
3048 	{
3049 	  free(image->id);
3050 	  free(image->name);
3051 	}
3052 	
3053 	extern "C" void rbd_image_spec_list_cleanup(rbd_image_spec_t *images,
3054 	                                            size_t num_images)
3055 	{
3056 	  for (size_t idx = 0; idx < num_images; ++idx) {
3057 	    rbd_image_spec_cleanup(&images[idx]);
3058 	  }
3059 	}
3060 	
3061 	extern "C" void rbd_linked_image_spec_cleanup(rbd_linked_image_spec_t *image)
3062 	{
3063 	  free(image->pool_name);
3064 	  free(image->pool_namespace);
3065 	  free(image->image_id);
3066 	  free(image->image_name);
3067 	}
3068 	
3069 	extern "C" void rbd_linked_image_spec_list_cleanup(
3070 	    rbd_linked_image_spec_t *images, size_t num_images)
3071 	{
3072 	  for (size_t idx = 0; idx < num_images; ++idx) {
3073 	    rbd_linked_image_spec_cleanup(&images[idx]);
3074 	  }
3075 	}
3076 	
3077 	extern "C" void rbd_snap_spec_cleanup(rbd_snap_spec_t *snap)
3078 	{
3079 	  free(snap->name);
3080 	}
3081 	
3082 	/* images */
3083 	extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size)
3084 	{
3085 	  librados::IoCtx io_ctx;
3086 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3087 	
3088 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3089 	  tracepoint(librbd, list_enter, io_ctx.get_pool_name().c_str(),
3090 	             io_ctx.get_id());
3091 	  std::vector<librbd::image_spec_t> cpp_image_specs;
3092 	  int r = librbd::api::Image<>::list_images(io_ctx, &cpp_image_specs);
3093 	  if (r < 0) {
3094 	    tracepoint(librbd, list_exit, r, *size);
3095 	    return r;
3096 	  }
3097 	
3098 	  size_t expected_size = 0;
3099 	
3100 	  for (auto& it : cpp_image_specs) {
3101 	    expected_size += it.name.size() + 1;
3102 	  }
3103 	  if (*size < expected_size) {
3104 	    *size = expected_size;
3105 	    tracepoint(librbd, list_exit, -ERANGE, *size);
3106 	    return -ERANGE;
3107 	  }
3108 	
3109 	  if (names == NULL) {
3110 	    tracepoint(librbd, list_exit, -EINVAL, *size);
3111 	    return -EINVAL;
3112 	  }
3113 	
3114 	  for (auto& it : cpp_image_specs) {
3115 	    const char* name = it.name.c_str();
3116 	    tracepoint(librbd, list_entry, name);
3117 	    strcpy(names, name);
3118 	    names += strlen(names) + 1;
3119 	  }
3120 	  tracepoint(librbd, list_exit, (int)expected_size, *size);
3121 	  return (int)expected_size;
3122 	}
3123 	
3124 	extern "C" int rbd_list2(rados_ioctx_t p, rbd_image_spec_t *images,
3125 	                         size_t *size)
3126 	{
3127 	  librados::IoCtx io_ctx;
3128 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3129 	
3130 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3131 	  tracepoint(librbd, list_enter, io_ctx.get_pool_name().c_str(),
3132 	             io_ctx.get_id());
3133 	  memset(images, 0, sizeof(*images) * *size);
3134 	  std::vector<librbd::image_spec_t> cpp_image_specs;
3135 	  int r = librbd::api::Image<>::list_images(io_ctx, &cpp_image_specs);
3136 	  if (r < 0) {
3137 	    tracepoint(librbd, list_exit, r, *size);
3138 	    return r;
3139 	  }
3140 	
3141 	  size_t expected_size = cpp_image_specs.size();
3142 	  if (*size < expected_size) {
3143 	    *size = expected_size;
3144 	    tracepoint(librbd, list_exit, -ERANGE, *size);
3145 	    return -ERANGE;
3146 	  }
3147 	
3148 	  *size = expected_size;
3149 	  for (size_t idx = 0; idx < expected_size; ++idx) {
3150 	    images[idx].id = strdup(cpp_image_specs[idx].id.c_str());
3151 	    images[idx].name = strdup(cpp_image_specs[idx].name.c_str());
3152 	  }
3153 	  tracepoint(librbd, list_exit, 0, *size);
3154 	  return 0;
3155 	}
3156 	
3157 	extern "C" int rbd_create(rados_ioctx_t p, const char *name, uint64_t size, int *order)
3158 	{
3159 	  librados::IoCtx io_ctx;
3160 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3161 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3162 	  tracepoint(librbd, create_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, *order);
3163 	  int r = librbd::create(io_ctx, name, size, order);
3164 	  tracepoint(librbd, create_exit, r, *order);
3165 	  return r;
3166 	}
3167 	
3168 	extern "C" int rbd_create2(rados_ioctx_t p, const char *name,
3169 				   uint64_t size, uint64_t features,
3170 				   int *order)
3171 	{
3172 	  librados::IoCtx io_ctx;
3173 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3174 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3175 	  tracepoint(librbd, create2_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, features, *order);
3176 	  int r = librbd::create(io_ctx, name, size, false, features, order, 0, 0);
3177 	  tracepoint(librbd, create2_exit, r, *order);
3178 	  return r;
3179 	}
3180 	
3181 	extern "C" int rbd_create3(rados_ioctx_t p, const char *name,
3182 				   uint64_t size, uint64_t features,
3183 				   int *order,
3184 				   uint64_t stripe_unit, uint64_t stripe_count)
3185 	{
3186 	  librados::IoCtx io_ctx;
3187 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3188 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3189 	  tracepoint(librbd, create3_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, features, *order, stripe_unit, stripe_count);
3190 	  int r = librbd::create(io_ctx, name, size, false, features, order,
3191 				stripe_unit, stripe_count);
3192 	  tracepoint(librbd, create3_exit, r, *order);
3193 	  return r;
3194 	}
3195 	
3196 	extern "C" int rbd_create4(rados_ioctx_t p, const char *name,
3197 				   uint64_t size, rbd_image_options_t opts)
3198 	{
3199 	  librados::IoCtx io_ctx;
3200 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3201 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3202 	  tracepoint(librbd, create4_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, opts);
3203 	  librbd::ImageOptions opts_(opts);
3204 	  int r = librbd::create(io_ctx, name, "", size, opts_, "", "", false);
3205 	  tracepoint(librbd, create4_exit, r);
3206 	  return r;
3207 	}
3208 	
3209 	extern "C" int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name,
3210 				 const char *p_snap_name, rados_ioctx_t c_ioctx,
3211 				 const char *c_name, uint64_t features, int *c_order)
3212 	{
3213 	  librados::IoCtx p_ioc, c_ioc;
3214 	  librados::IoCtx::from_rados_ioctx_t(p_ioctx, p_ioc);
3215 	  librados::IoCtx::from_rados_ioctx_t(c_ioctx, c_ioc);
3216 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioc));
3217 	  tracepoint(librbd, clone_enter, p_ioc.get_pool_name().c_str(), p_ioc.get_id(), p_name, p_snap_name, c_ioc.get_pool_name().c_str(), c_ioc.get_id(), c_name, features);
3218 	  int r = librbd::clone(p_ioc, p_name, p_snap_name, c_ioc, c_name,
3219 			       features, c_order, 0, 0);
3220 	  tracepoint(librbd, clone_exit, r, *c_order);
3221 	  return r;
3222 	}
3223 	
3224 	extern "C" int rbd_clone2(rados_ioctx_t p_ioctx, const char *p_name,
3225 				  const char *p_snap_name, rados_ioctx_t c_ioctx,
3226 				  const char *c_name, uint64_t features, int *c_order,
3227 				  uint64_t stripe_unit, int stripe_count)
3228 	{
3229 	  librados::IoCtx p_ioc, c_ioc;
3230 	  librados::IoCtx::from_rados_ioctx_t(p_ioctx, p_ioc);
3231 	  librados::IoCtx::from_rados_ioctx_t(c_ioctx, c_ioc);
3232 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioc));
3233 	  tracepoint(librbd, clone2_enter, p_ioc.get_pool_name().c_str(), p_ioc.get_id(), p_name, p_snap_name, c_ioc.get_pool_name().c_str(), c_ioc.get_id(), c_name, features, stripe_unit, stripe_count);
3234 	  int r = librbd::clone(p_ioc, p_name, p_snap_name, c_ioc, c_name,
3235 			       features, c_order, stripe_unit, stripe_count);
3236 	  tracepoint(librbd, clone2_exit, r, *c_order);
3237 	  return r;
3238 	}
3239 	
3240 	extern "C" int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
3241 				  const char *p_snap_name, rados_ioctx_t c_ioctx,
3242 				  const char *c_name, rbd_image_options_t c_opts)
3243 	{
3244 	  librados::IoCtx p_ioc, c_ioc;
3245 	  librados::IoCtx::from_rados_ioctx_t(p_ioctx, p_ioc);
3246 	  librados::IoCtx::from_rados_ioctx_t(c_ioctx, c_ioc);
3247 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioc));
3248 	  tracepoint(librbd, clone3_enter, p_ioc.get_pool_name().c_str(), p_ioc.get_id(), p_name, p_snap_name, c_ioc.get_pool_name().c_str(), c_ioc.get_id(), c_name, c_opts);
3249 	  librbd::ImageOptions c_opts_(c_opts);
3250 	  int r = librbd::clone(p_ioc, nullptr, p_name, p_snap_name, c_ioc, nullptr,
3251 	                        c_name, c_opts_, "", "");
3252 	  tracepoint(librbd, clone3_exit, r);
3253 	  return r;
3254 	}
3255 	
3256 	extern "C" int rbd_remove(rados_ioctx_t p, const char *name)
3257 	{
3258 	  librados::IoCtx io_ctx;
3259 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3260 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3261 	  tracepoint(librbd, remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name);
3262 	  librbd::NoOpProgressContext prog_ctx;
3263 	  int r = librbd::api::Image<>::remove(io_ctx, name, prog_ctx);
3264 	  tracepoint(librbd, remove_exit, r);
3265 	  return r;
3266 	}
3267 	
3268 	extern "C" int rbd_remove_with_progress(rados_ioctx_t p, const char *name,
3269 						librbd_progress_fn_t cb, void *cbdata)
3270 	{
3271 	  librados::IoCtx io_ctx;
3272 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3273 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3274 	  tracepoint(librbd, remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name);
3275 	  librbd::CProgressContext prog_ctx(cb, cbdata);
3276 	  int r = librbd::api::Image<>::remove(io_ctx, name, prog_ctx);
3277 	  tracepoint(librbd, remove_exit, r);
3278 	  return r;
3279 	}
3280 	
3281 	extern "C" int rbd_trash_move(rados_ioctx_t p, const char *name,
3282 	                              uint64_t delay) {
3283 	  librados::IoCtx io_ctx;
3284 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3285 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3286 	  tracepoint(librbd, trash_move_enter, io_ctx.get_pool_name().c_str(),
3287 	             io_ctx.get_id(), name);
3288 	  int r = librbd::api::Trash<>::move(io_ctx, RBD_TRASH_IMAGE_SOURCE_USER, name,
3289 	                                     delay);
3290 	  tracepoint(librbd, trash_move_exit, r);
3291 	  return r;
3292 	}
3293 	
3294 	extern "C" int rbd_trash_get(rados_ioctx_t io, const char *id,
3295 	                             rbd_trash_image_info_t *info) {
3296 	  librados::IoCtx io_ctx;
3297 	  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
3298 	
3299 	  librbd::trash_image_info_t cpp_info;
3300 	  int r = librbd::api::Trash<>::get(io_ctx, id, &cpp_info);
3301 	  if (r < 0) {
3302 	    return r;
3303 	  }
3304 	
3305 	  trash_image_info_cpp_to_c(cpp_info, info);
3306 	  return 0;
3307 	}
3308 	
3309 	extern "C" void rbd_trash_get_cleanup(rbd_trash_image_info_t *info) {
3310 	  free(info->id);
3311 	  free(info->name);
3312 	}
3313 	
3314 	extern "C" int rbd_trash_list(rados_ioctx_t p, rbd_trash_image_info_t *entries,
3315 	                              size_t *num_entries) {
3316 	  librados::IoCtx io_ctx;
3317 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3318 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3319 	  tracepoint(librbd, trash_list_enter,
3320 	             io_ctx.get_pool_name().c_str(), io_ctx.get_id());
3321 	  memset(entries, 0, sizeof(*entries) * *num_entries);
3322 	
3323 	  vector<librbd::trash_image_info_t> cpp_entries;
3324 	  int r = librbd::api::Trash<>::list(io_ctx, cpp_entries, true);
3325 	  if (r < 0) {
3326 	    tracepoint(librbd, trash_list_exit, r, *num_entries);
3327 	    return r;
3328 	  }
3329 	
3330 	  if (*num_entries < cpp_entries.size()) {
3331 	    *num_entries = cpp_entries.size();
3332 	    tracepoint(librbd, trash_list_exit, -ERANGE, *num_entries);
3333 	    return -ERANGE;
3334 	  }
3335 	
3336 	  int i=0;
3337 	  for (const auto &entry : cpp_entries) {
3338 	    trash_image_info_cpp_to_c(entry, &entries[i++]);
3339 	  }
3340 	  *num_entries = cpp_entries.size();
3341 	
3342 	  return *num_entries;
3343 	}
3344 	
3345 	extern "C" void rbd_trash_list_cleanup(rbd_trash_image_info_t *entries,
3346 	                                       size_t num_entries) {
3347 	  for (size_t i=0; i < num_entries; i++) {
3348 	    rbd_trash_get_cleanup(&entries[i]);
3349 	  }
3350 	}
3351 	
3352 	extern "C" int rbd_trash_purge(rados_ioctx_t io, time_t expire_ts,
3353 					                       float threshold) {
3354 		librados::IoCtx io_ctx;
3355 		librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
3356 		TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3357 		tracepoint(librbd, trash_purge_enter, io_ctx.get_pool_name().c_str(),
3358 		           io_ctx.get_id(), expire_ts, threshold);
3359 	        librbd::NoOpProgressContext nop_pctx;
3360 	        int r = librbd::api::Trash<>::purge(io_ctx, expire_ts, threshold, nop_pctx);
3361 		tracepoint(librbd, trash_purge_exit, r);
3362 		return r;
3363 	}
3364 	
3365 	extern "C" int rbd_trash_purge_with_progress(rados_ioctx_t io, time_t expire_ts,
3366 					float threshold, librbd_progress_fn_t cb, void* cbdata) {
3367 		librados::IoCtx io_ctx;
3368 		librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
3369 		TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3370 		tracepoint(librbd, trash_purge_enter, io_ctx.get_pool_name().c_str(),
3371 		           io_ctx.get_id(), expire_ts, threshold);
3372 		librbd::CProgressContext pctx(cb, cbdata);
3373 		int r = librbd::api::Trash<>::purge(io_ctx, expire_ts, threshold, pctx);
3374 		tracepoint(librbd, trash_purge_exit, r);
3375 		return r;
3376 	}
3377 	
3378 	extern "C" int rbd_trash_remove(rados_ioctx_t p, const char *image_id,
3379 	                                bool force) {
3380 	  librados::IoCtx io_ctx;
3381 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3382 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3383 	  tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
3384 	             io_ctx.get_id(), image_id, force);
3385 	  librbd::NoOpProgressContext prog_ctx;
3386 	  int r = librbd::api::Trash<>::remove(io_ctx, image_id, force, prog_ctx);
3387 	  tracepoint(librbd, trash_remove_exit, r);
3388 	  return r;
3389 	}
3390 	
3391 	extern "C" int rbd_trash_remove_with_progress(rados_ioctx_t p,
3392 	                                              const char *image_id,
3393 	                                              bool force,
3394 	                                              librbd_progress_fn_t cb,
3395 	                                              void *cbdata) {
3396 	  librados::IoCtx io_ctx;
3397 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3398 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3399 	  tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
3400 	             io_ctx.get_id(), image_id, force);
3401 	  librbd::CProgressContext prog_ctx(cb, cbdata);
3402 	  int r = librbd::api::Trash<>::remove(io_ctx, image_id, force, prog_ctx);
3403 	  tracepoint(librbd, trash_remove_exit, r);
3404 	  return r;
3405 	}
3406 	
3407 	extern "C" int rbd_trash_restore(rados_ioctx_t p, const char *id,
3408 	                                 const char *name) {
3409 	  librados::IoCtx io_ctx;
3410 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3411 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3412 	  tracepoint(librbd, trash_undelete_enter, io_ctx.get_pool_name().c_str(),
3413 	             io_ctx.get_id(), id, name);
3414 	  int r = librbd::api::Trash<>::restore(
3415 	      io_ctx, librbd::api::Trash<>::RESTORE_SOURCE_WHITELIST, id, name);
3416 	  tracepoint(librbd, trash_undelete_exit, r);
3417 	  return r;
3418 	}
3419 	
3420 	extern "C" int rbd_namespace_create(rados_ioctx_t io,
3421 	                                    const char *namespace_name) {
3422 	  librados::IoCtx io_ctx;
3423 	  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
3424 	
3425 	  return librbd::api::Namespace<>::create(io_ctx, namespace_name);
3426 	}
3427 	
3428 	extern "C" int rbd_namespace_remove(rados_ioctx_t io,
3429 	                                    const char *namespace_name) {
3430 	  librados::IoCtx io_ctx;
3431 	  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
3432 	
3433 	  return librbd::api::Namespace<>::remove(io_ctx, namespace_name);
3434 	}
3435 	
3436 	extern "C" int rbd_namespace_list(rados_ioctx_t io, char *names, size_t *size) {
3437 	  librados::IoCtx io_ctx;
3438 	  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
3439 	
3440 	  if (names == nullptr || size == nullptr) {
3441 	    return -EINVAL;
3442 	  }
3443 	
3444 	  std::vector<std::string> cpp_names;
3445 	  int r = librbd::api::Namespace<>::list(io_ctx, &cpp_names);
3446 	  if (r < 0) {
3447 	    return r;
3448 	  }
3449 	
3450 	  size_t expected_size = 0;
3451 	  for (size_t i = 0; i < cpp_names.size(); i++) {
3452 	    expected_size += cpp_names[i].size() + 1;
3453 	  }
3454 	  if (*size < expected_size) {
3455 	    *size = expected_size;
3456 	    return -ERANGE;
3457 	  }
3458 	
3459 	  *size = expected_size;
3460 	  for (int i = 0; i < (int)cpp_names.size(); i++) {
3461 	    const char* name = cpp_names[i].c_str();
3462 	    strcpy(names, name);
3463 	    names += strlen(names) + 1;
3464 	  }
3465 	
3466 	  return (int)expected_size;
3467 	}
3468 	
3469 	extern "C" int rbd_namespace_exists(rados_ioctx_t io,
3470 	                                    const char *namespace_name,
3471 	                                    bool *exists) {
3472 	  librados::IoCtx io_ctx;
3473 	  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
3474 	
3475 	  return librbd::api::Namespace<>::exists(io_ctx, namespace_name, exists);
3476 	}
3477 	
3478 	extern "C" int rbd_pool_init(rados_ioctx_t io, bool force) {
3479 	  librados::IoCtx io_ctx;
3480 	  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
3481 	
3482 	  return librbd::api::Pool<>::init(io_ctx, force);
3483 	}
3484 	
3485 	extern "C" void rbd_pool_stats_create(rbd_pool_stats_t *stats) {
3486 	  *stats = reinterpret_cast<rbd_pool_stats_t>(
3487 	    new librbd::api::Pool<>::StatOptions{});
3488 	}
3489 	
3490 	extern "C" void rbd_pool_stats_destroy(rbd_pool_stats_t stats) {
3491 	  auto pool_stat_options =
3492 	    reinterpret_cast<librbd::api::Pool<>::StatOptions*>(stats);
3493 	  delete pool_stat_options;
3494 	}
3495 	
3496 	extern "C" int rbd_pool_stats_option_add_uint64(rbd_pool_stats_t stats,
3497 	                                                int stat_option,
3498 	                                                uint64_t* stat_val) {
3499 	  auto pool_stat_options =
3500 	    reinterpret_cast<librbd::api::Pool<>::StatOptions*>(stats);
3501 	  return librbd::api::Pool<>::add_stat_option(
3502 	    pool_stat_options, static_cast<rbd_pool_stat_option_t>(stat_option),
3503 	    stat_val);
3504 	}
3505 	
3506 	extern "C" int rbd_pool_stats_get(
3507 	    rados_ioctx_t io, rbd_pool_stats_t pool_stats) {
3508 	  librados::IoCtx io_ctx;
3509 	  librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
3510 	
3511 	  auto pool_stat_options =
3512 	    reinterpret_cast<librbd::api::Pool<>::StatOptions*>(pool_stats);
3513 	  return librbd::api::Pool<>::get_stats(io_ctx, pool_stat_options);
3514 	}
3515 	
3516 	extern "C" int rbd_copy(rbd_image_t image, rados_ioctx_t dest_p,
3517 				const char *destname)
3518 	{
3519 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3520 	  librados::IoCtx dest_io_ctx;
3521 	  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
3522 	  tracepoint(librbd, copy_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname);
3523 	  librbd::ImageOptions opts;
3524 	  librbd::NoOpProgressContext prog_ctx;
3525 	  int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, 0);
3526 	  tracepoint(librbd, copy_exit, r);
3527 	  return r;
3528 	}
3529 	
3530 	extern "C" int rbd_copy2(rbd_image_t srcp, rbd_image_t destp)
3531 	{
3532 	  librbd::ImageCtx *src = (librbd::ImageCtx *)srcp;
3533 	  librbd::ImageCtx *dest = (librbd::ImageCtx *)destp;
3534 	  tracepoint(librbd, copy2_enter, src, src->name.c_str(), src->snap_name.c_str(), src->read_only, dest, dest->name.c_str(), dest->snap_name.c_str(), dest->read_only);
3535 	  librbd::NoOpProgressContext prog_ctx;
3536 	  int r = librbd::copy(src, dest, prog_ctx, 0);
3537 	  tracepoint(librbd, copy2_exit, r);
3538 	  return r;
3539 	}
3540 	
3541 	extern "C" int rbd_copy3(rbd_image_t image, rados_ioctx_t dest_p,
3542 				 const char *destname, rbd_image_options_t c_opts)
3543 	{
3544 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3545 	  librados::IoCtx dest_io_ctx;
3546 	  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
3547 	  tracepoint(librbd, copy3_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, c_opts);
3548 	  librbd::ImageOptions c_opts_(c_opts);
3549 	  librbd::NoOpProgressContext prog_ctx;
3550 	  int r = librbd::copy(ictx, dest_io_ctx, destname, c_opts_, prog_ctx, 0);
3551 	  tracepoint(librbd, copy3_exit, r);
3552 	  return r;
3553 	}
3554 	
3555 	extern "C" int rbd_copy4(rbd_image_t image, rados_ioctx_t dest_p,
3556 	                         const char *destname, rbd_image_options_t c_opts, size_t sparse_size)
3557 	{
3558 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3559 	  librados::IoCtx dest_io_ctx;
3560 	  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
3561 	  tracepoint(librbd, copy4_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, c_opts, sparse_size);
3562 	  librbd::ImageOptions c_opts_(c_opts);
3563 	  librbd::NoOpProgressContext prog_ctx;
3564 	  int r = librbd::copy(ictx, dest_io_ctx, destname, c_opts_, prog_ctx, sparse_size);
3565 	  tracepoint(librbd, copy4_exit, r);
3566 	  return r;
3567 	}
3568 	
3569 	extern "C" int rbd_copy_with_progress(rbd_image_t image, rados_ioctx_t dest_p,
3570 					      const char *destname,
3571 					      librbd_progress_fn_t fn, void *data)
3572 	{
3573 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3574 	  librados::IoCtx dest_io_ctx;
3575 	  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
3576 	  tracepoint(librbd, copy_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname);
3577 	  librbd::ImageOptions opts;
3578 	  librbd::CProgressContext prog_ctx(fn, data);
3579 	  int ret = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, 0);
3580 	  tracepoint(librbd, copy_exit, ret);
3581 	  return ret;
3582 	}
3583 	
3584 	extern "C" int rbd_copy_with_progress2(rbd_image_t srcp, rbd_image_t destp,
3585 					      librbd_progress_fn_t fn, void *data)
3586 	{
3587 	  librbd::ImageCtx *src = (librbd::ImageCtx *)srcp;
3588 	  librbd::ImageCtx *dest = (librbd::ImageCtx *)destp;
3589 	  tracepoint(librbd, copy2_enter, src, src->name.c_str(), src->snap_name.c_str(), src->read_only, dest, dest->name.c_str(), dest->snap_name.c_str(), dest->read_only);
3590 	  librbd::CProgressContext prog_ctx(fn, data);
3591 	  int ret = librbd::copy(src, dest, prog_ctx, 0);
3592 	  tracepoint(librbd, copy2_exit, ret);
3593 	  return ret;
3594 	}
3595 	
3596 	extern "C" int rbd_copy_with_progress3(rbd_image_t image, rados_ioctx_t dest_p,
3597 					       const char *destname,
3598 					       rbd_image_options_t dest_opts,
3599 					       librbd_progress_fn_t fn, void *data)
3600 	{
3601 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3602 	  librados::IoCtx dest_io_ctx;
3603 	  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
3604 	  tracepoint(librbd, copy3_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, dest_opts);
3605 	  librbd::ImageOptions dest_opts_(dest_opts);
3606 	  librbd::CProgressContext prog_ctx(fn, data);
3607 	  int ret = librbd::copy(ictx, dest_io_ctx, destname, dest_opts_, prog_ctx, 0);
3608 	  tracepoint(librbd, copy3_exit, ret);
3609 	  return ret;
3610 	}
3611 	
3612 	extern "C" int rbd_copy_with_progress4(rbd_image_t image, rados_ioctx_t dest_p,
3613 	                                       const char *destname,
3614 	                                       rbd_image_options_t dest_opts,
3615 	                                       librbd_progress_fn_t fn, void *data, size_t sparse_size)
3616 	{
3617 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3618 	  librados::IoCtx dest_io_ctx;
3619 	  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
3620 	  tracepoint(librbd, copy4_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(), destname, dest_opts, sparse_size);
3621 	  librbd::ImageOptions dest_opts_(dest_opts);
3622 	  librbd::CProgressContext prog_ctx(fn, data);
3623 	  int ret = librbd::copy(ictx, dest_io_ctx, destname, dest_opts_, prog_ctx, sparse_size);
3624 	  tracepoint(librbd, copy4_exit, ret);
3625 	  return ret;
3626 	}
3627 	
3628 	extern "C" int rbd_deep_copy(rbd_image_t image, rados_ioctx_t dest_p,
3629 	                             const char *destname, rbd_image_options_t c_opts)
3630 	{
3631 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3632 	  librados::IoCtx dest_io_ctx;
3633 	  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
3634 	  tracepoint(librbd, deep_copy_enter, ictx, ictx->name.c_str(),
3635 	             ictx->snap_name.c_str(), ictx->read_only,
3636 	             dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(),
3637 	             destname, c_opts);
3638 	  librbd::ImageOptions opts(c_opts);
3639 	  librbd::NoOpProgressContext prog_ctx;
3640 	  int r = librbd::api::Image<>::deep_copy(ictx, dest_io_ctx, destname, opts,
3641 	                                          prog_ctx);
3642 	  tracepoint(librbd, deep_copy_exit, r);
3643 	  return r;
3644 	}
3645 	
3646 	extern "C" int rbd_deep_copy_with_progress(rbd_image_t image,
3647 	                                           rados_ioctx_t dest_p,
3648 	                                           const char *destname,
3649 	                                           rbd_image_options_t dest_opts,
3650 	                                           librbd_progress_fn_t fn, void *data)
3651 	{
3652 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3653 	  librados::IoCtx dest_io_ctx;
3654 	  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
3655 	  tracepoint(librbd, deep_copy_enter, ictx, ictx->name.c_str(),
3656 	             ictx->snap_name.c_str(), ictx->read_only,
3657 	             dest_io_ctx.get_pool_name().c_str(), dest_io_ctx.get_id(),
3658 	             destname, dest_opts);
3659 	  librbd::ImageOptions opts(dest_opts);
3660 	  librbd::CProgressContext prog_ctx(fn, data);
3661 	  int ret = librbd::api::Image<>::deep_copy(ictx, dest_io_ctx, destname, opts,
3662 	                                            prog_ctx);
3663 	  tracepoint(librbd, deep_copy_exit, ret);
3664 	  return ret;
3665 	}
3666 	
3667 	extern "C" int rbd_flatten(rbd_image_t image)
3668 	{
3669 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3670 	  tracepoint(librbd, flatten_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
3671 	  librbd::NoOpProgressContext prog_ctx;
3672 	  int r = ictx->operations->flatten(prog_ctx);
3673 	  tracepoint(librbd, flatten_exit, r);
3674 	  return r;
3675 	}
3676 	
3677 	extern "C" int rbd_flatten_with_progress(rbd_image_t image,
3678 						 librbd_progress_fn_t cb, void *cbdata)
3679 	{
3680 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3681 	  tracepoint(librbd, flatten_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
3682 	  librbd::CProgressContext prog_ctx(cb, cbdata);
3683 	  int r = ictx->operations->flatten(prog_ctx);
3684 	  tracepoint(librbd, flatten_exit, r);
3685 	  return r;
3686 	}
3687 	
3688 	extern "C" int rbd_sparsify(rbd_image_t image, size_t sparse_size)
3689 	{
3690 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3691 	  tracepoint(librbd, sparsify_enter, ictx, ictx->name.c_str(), sparse_size,
3692 	             ictx->id.c_str());
3693 	  librbd::NoOpProgressContext prog_ctx;
3694 	  int r = ictx->operations->sparsify(sparse_size, prog_ctx);
3695 	  tracepoint(librbd, sparsify_exit, r);
3696 	  return r;
3697 	}
3698 	
3699 	extern "C" int rbd_sparsify_with_progress(rbd_image_t image, size_t sparse_size,
3700 	                                          librbd_progress_fn_t cb, void *cbdata)
3701 	{
3702 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3703 	  tracepoint(librbd, sparsify_enter, ictx, ictx->name.c_str(), sparse_size,
3704 	             ictx->id.c_str());
3705 	  librbd::CProgressContext prog_ctx(cb, cbdata);
3706 	  int r = ictx->operations->sparsify(sparse_size, prog_ctx);
3707 	  tracepoint(librbd, sparsify_exit, r);
3708 	  return r;
3709 	}
3710 	
3711 	extern "C" int rbd_rename(rados_ioctx_t src_p, const char *srcname,
3712 				  const char *destname)
3713 	{
3714 	  librados::IoCtx src_io_ctx;
3715 	  librados::IoCtx::from_rados_ioctx_t(src_p, src_io_ctx);
3716 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(src_io_ctx));
3717 	  tracepoint(librbd, rename_enter, src_io_ctx.get_pool_name().c_str(), src_io_ctx.get_id(), srcname, destname);
3718 	  int r = librbd::rename(src_io_ctx, srcname, destname);
3719 	  tracepoint(librbd, rename_exit, r);
3720 	  return r;
3721 	}
3722 	
3723 	extern "C" int rbd_migration_prepare(rados_ioctx_t p, const char *image_name,
3724 	                                     rados_ioctx_t dest_p,
3725 	                                     const char *dest_image_name,
3726 	                                     rbd_image_options_t opts_)
3727 	{
3728 	  librados::IoCtx io_ctx;
3729 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3730 	  librados::IoCtx dest_io_ctx;
3731 	  librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
3732 	  tracepoint(librbd, migration_prepare_enter, io_ctx.get_pool_name().c_str(),
3733 	             io_ctx.get_id(), image_name, dest_io_ctx.get_pool_name().c_str(),
3734 	             dest_io_ctx.get_id(), dest_image_name, opts_);
3735 	  librbd::ImageOptions opts(opts_);
3736 	  int r = librbd::api::Migration<>::prepare(io_ctx, image_name, dest_io_ctx,
3737 	                                            dest_image_name, opts);
3738 	  tracepoint(librbd, migration_prepare_exit, r);
3739 	  return r;
3740 	}
3741 	
3742 	extern "C" int rbd_migration_execute(rados_ioctx_t p, const char *image_name)
3743 	{
3744 	  librados::IoCtx io_ctx;
3745 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3746 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3747 	  tracepoint(librbd, migration_execute_enter, io_ctx.get_pool_name().c_str(),
3748 	             io_ctx.get_id(), image_name);
3749 	  librbd::NoOpProgressContext prog_ctx;
3750 	  int r = librbd::api::Migration<>::execute(io_ctx, image_name, prog_ctx);
3751 	  tracepoint(librbd, migration_execute_exit, r);
3752 	  return r;
3753 	}
3754 	
3755 	extern "C" int rbd_migration_execute_with_progress(rados_ioctx_t p,
3756 	                                                   const char *name,
3757 	                                                   librbd_progress_fn_t fn,
3758 	                                                   void *data)
3759 	{
3760 	  librados::IoCtx io_ctx;
3761 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3762 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3763 	  tracepoint(librbd, migration_execute_enter, io_ctx.get_pool_name().c_str(),
3764 	             io_ctx.get_id(), name);
3765 	  librbd::CProgressContext prog_ctx(fn, data);
3766 	  int r = librbd::api::Migration<>::execute(io_ctx, name, prog_ctx);
3767 	  tracepoint(librbd, migration_execute_exit, r);
3768 	  return r;
3769 	}
3770 	
3771 	extern "C" int rbd_migration_abort(rados_ioctx_t p, const char *image_name)
3772 	{
3773 	  librados::IoCtx io_ctx;
3774 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3775 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3776 	  tracepoint(librbd, migration_abort_enter, io_ctx.get_pool_name().c_str(),
3777 	             io_ctx.get_id(), image_name);
3778 	  librbd::NoOpProgressContext prog_ctx;
3779 	  int r = librbd::api::Migration<>::abort(io_ctx, image_name, prog_ctx);
3780 	  tracepoint(librbd, migration_abort_exit, r);
3781 	  return r;
3782 	}
3783 	
3784 	extern "C" int rbd_migration_abort_with_progress(rados_ioctx_t p,
3785 	                                                 const char *name,
3786 	                                                 librbd_progress_fn_t fn,
3787 	                                                 void *data)
3788 	{
3789 	  librados::IoCtx io_ctx;
3790 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3791 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3792 	  tracepoint(librbd, migration_abort_enter, io_ctx.get_pool_name().c_str(),
3793 	             io_ctx.get_id(), name);
3794 	  librbd::CProgressContext prog_ctx(fn, data);
3795 	  int r = librbd::api::Migration<>::abort(io_ctx, name, prog_ctx);
3796 	  tracepoint(librbd, migration_abort_exit, r);
3797 	  return r;
3798 	}
3799 	
3800 	extern "C" int rbd_migration_commit(rados_ioctx_t p, const char *image_name)
3801 	{
3802 	  librados::IoCtx io_ctx;
3803 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3804 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3805 	  tracepoint(librbd, migration_commit_enter, io_ctx.get_pool_name().c_str(),
3806 	             io_ctx.get_id(), image_name);
3807 	  librbd::NoOpProgressContext prog_ctx;
3808 	  int r = librbd::api::Migration<>::commit(io_ctx, image_name, prog_ctx);
3809 	  tracepoint(librbd, migration_commit_exit, r);
3810 	  return r;
3811 	}
3812 	
3813 	extern "C" int rbd_migration_commit_with_progress(rados_ioctx_t p,
3814 	                                                  const char *name,
3815 	                                                  librbd_progress_fn_t fn,
3816 	                                                  void *data)
3817 	{
3818 	  librados::IoCtx io_ctx;
3819 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3820 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3821 	  tracepoint(librbd, migration_commit_enter, io_ctx.get_pool_name().c_str(),
3822 	             io_ctx.get_id(), name);
3823 	  librbd::CProgressContext prog_ctx(fn, data);
3824 	  int r = librbd::api::Migration<>::commit(io_ctx, name, prog_ctx);
3825 	  tracepoint(librbd, migration_commit_exit, r);
3826 	  return r;
3827 	}
3828 	
3829 	extern "C" int rbd_migration_status(rados_ioctx_t p, const char *image_name,
3830 	                                    rbd_image_migration_status_t *status,
3831 	                                    size_t status_size)
3832 	{
3833 	  librados::IoCtx io_ctx;
3834 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3835 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3836 	  tracepoint(librbd, migration_status_enter, io_ctx.get_pool_name().c_str(),
3837 	             io_ctx.get_id(), image_name);
3838 	
3839 	  if (status_size != sizeof(rbd_image_migration_status_t)) {
3840 	    tracepoint(librbd, migration_status_exit, -ERANGE);
3841 	    return -ERANGE;
3842 	  }
3843 	
3844 	  librbd::image_migration_status_t cpp_status;
3845 	  int r = librbd::api::Migration<>::status(io_ctx, image_name, &cpp_status);
3846 	  if (r >= 0) {
3847 	    status->source_pool_id = cpp_status.source_pool_id;
3848 	    status->source_pool_namespace =
3849 	      strdup(cpp_status.source_pool_namespace.c_str());
3850 	    status->source_image_name = strdup(cpp_status.source_image_name.c_str());
3851 	    status->source_image_id = strdup(cpp_status.source_image_id.c_str());
3852 	    status->dest_pool_id = cpp_status.dest_pool_id;
3853 	    status->dest_pool_namespace =
3854 	      strdup(cpp_status.dest_pool_namespace.c_str());
3855 	    status->dest_image_name = strdup(cpp_status.dest_image_name.c_str());
3856 	    status->dest_image_id = strdup(cpp_status.dest_image_id.c_str());
3857 	    status->state = cpp_status.state;
3858 	    status->state_description = strdup(cpp_status.state_description.c_str());
3859 	  }
3860 	
3861 	  tracepoint(librbd, migration_status_exit, r);
3862 	  return r;
3863 	}
3864 	
3865 	extern "C" void rbd_migration_status_cleanup(rbd_image_migration_status_t *s)
3866 	{
3867 	  free(s->source_pool_namespace);
3868 	  free(s->source_image_name);
3869 	  free(s->source_image_id);
3870 	  free(s->dest_pool_namespace);
3871 	  free(s->dest_image_name);
3872 	  free(s->dest_image_id);
3873 	  free(s->state_description);
3874 	}
3875 	
3876 	extern "C" int rbd_pool_metadata_get(rados_ioctx_t p, const char *key,
3877 	                                     char *value, size_t *vallen)
3878 	{
3879 	  librados::IoCtx io_ctx;
3880 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3881 	  string val_s;
3882 	  int r = librbd::api::PoolMetadata<>::get(io_ctx, key, &val_s);
3883 	  if (*vallen < val_s.size() + 1) {
3884 	    r = -ERANGE;
3885 	    *vallen = val_s.size() + 1;
3886 	  } else {
3887 	    strncpy(value, val_s.c_str(), val_s.size() + 1);
3888 	  }
3889 	
3890 	  return r;
3891 	}
3892 	
3893 	extern "C" int rbd_pool_metadata_set(rados_ioctx_t p, const char *key,
3894 	                                     const char *value)
3895 	{
3896 	  librados::IoCtx io_ctx;
3897 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3898 	  int r = librbd::api::PoolMetadata<>::set(io_ctx, key, value);
3899 	  return r;
3900 	}
3901 	
3902 	extern "C" int rbd_pool_metadata_remove(rados_ioctx_t p, const char *key)
3903 	{
3904 	  librados::IoCtx io_ctx;
3905 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3906 	  int r = librbd::api::PoolMetadata<>::remove(io_ctx, key);
3907 	  return r;
3908 	}
3909 	
3910 	extern "C" int rbd_pool_metadata_list(rados_ioctx_t p, const char *start,
3911 	                                      uint64_t max, char *key, size_t *key_len,
3912 	                                      char *value, size_t *val_len)
3913 	{
3914 	  librados::IoCtx io_ctx;
3915 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3916 	  map<string, bufferlist> pairs;
3917 	  int r = librbd::api::PoolMetadata<>::list(io_ctx, start, max, &pairs);
3918 	  if (r < 0) {
3919 	    return r;
3920 	  }
3921 	  size_t key_total_len = 0, val_total_len = 0;
3922 	  for (auto &it : pairs) {
3923 	    key_total_len += it.first.size() + 1;
3924 	    val_total_len += it.second.length() + 1;
3925 	  }
3926 	  if (*key_len < key_total_len || *val_len < val_total_len) {
3927 	    *key_len = key_total_len;
3928 	    *val_len = val_total_len;
3929 	    return -ERANGE;
3930 	  }
3931 	  *key_len = key_total_len;
3932 	  *val_len = val_total_len;
3933 	
3934 	  char *key_p = key, *value_p = value;
3935 	  for (auto &it : pairs) {
3936 	    strncpy(key_p, it.first.c_str(), it.first.size() + 1);
3937 	    key_p += it.first.size() + 1;
3938 	    strncpy(value_p, it.second.c_str(), it.second.length());
3939 	    value_p += it.second.length();
3940 	    *value_p = '\0';
3941 	    value_p++;
3942 	  }
3943 	  return 0;
3944 	}
3945 	
3946 	extern "C" int rbd_config_pool_list(rados_ioctx_t p,
3947 	                                    rbd_config_option_t *options,
3948 	                                    int *max_options) {
3949 	  librados::IoCtx io_ctx;
3950 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3951 	
3952 	  std::vector<librbd::config_option_t> option_vector;
3953 	  int r = librbd::api::Config<>::list(io_ctx, &option_vector);
3954 	  if (r < 0) {
3955 	    return r;
3956 	  }
3957 	
3958 	  if (*max_options < static_cast<int>(option_vector.size())) {
3959 	    *max_options = static_cast<int>(option_vector.size());
3960 	    return -ERANGE;
3961 	  }
3962 	
3963 	  for (int i = 0; i < static_cast<int>(option_vector.size()); ++i) {
3964 	    config_option_cpp_to_c(option_vector[i], &options[i]);
3965 	  }
3966 	  *max_options = static_cast<int>(option_vector.size());
3967 	  return 0;
3968 	}
3969 	
3970 	extern "C" void rbd_config_pool_list_cleanup(rbd_config_option_t *options,
3971 	                                             int max_options) {
3972 	  for (int i = 0; i < max_options; ++i) {
3973 	    config_option_cleanup(options[i]);
3974 	  }
3975 	}
3976 	
3977 	extern "C" int rbd_open(rados_ioctx_t p, const char *name, rbd_image_t *image,
3978 				const char *snap_name)
3979 	{
3980 	  librados::IoCtx io_ctx;
3981 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
3982 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
3983 	  librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx,
3984 							false);
3985 	  tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
3986 	
3987 	  int r = ictx->state->open(0);
3988 	  if (r >= 0) {
3989 	    *image = (rbd_image_t)ictx;
3990 	  }
3991 	  tracepoint(librbd, open_image_exit, r);
3992 	  return r;
3993 	}
3994 	
3995 	extern "C" int rbd_open_by_id(rados_ioctx_t p, const char *id,
3996 	                              rbd_image_t *image, const char *snap_name)
3997 	{
3998 	  librados::IoCtx io_ctx;
3999 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
4000 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
4001 	  librbd::ImageCtx *ictx = new librbd::ImageCtx("", id, snap_name, io_ctx,
4002 							false);
4003 	  tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(),
4004 	             ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4005 	
4006 	  int r = ictx->state->open(0);
4007 	  if (r < 0) {
4008 	    delete ictx;
4009 	  } else {
4010 	    *image = (rbd_image_t)ictx;
4011 	  }
4012 	  tracepoint(librbd, open_image_exit, r);
4013 	  return r;
4014 	}
4015 	
4016 	extern "C" int rbd_aio_open(rados_ioctx_t p, const char *name,
4017 				    rbd_image_t *image, const char *snap_name,
4018 				    rbd_completion_t c)
4019 	{
4020 	  librados::IoCtx io_ctx;
4021 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
4022 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
4023 	  librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx,
4024 							false);
4025 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
4026 	  tracepoint(librbd, aio_open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only, comp->pc);
4027 	  ictx->state->open(0, new C_OpenComplete(ictx, get_aio_completion(comp),
4028 	                                          image));
4029 	  tracepoint(librbd, aio_open_image_exit, 0);
4030 	  return 0;
4031 	}
4032 	
4033 	extern "C" int rbd_aio_open_by_id(rados_ioctx_t p, const char *id,
4034 				          rbd_image_t *image, const char *snap_name,
4035 				          rbd_completion_t c)
4036 	{
4037 	  librados::IoCtx io_ctx;
4038 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
4039 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
4040 	  librbd::ImageCtx *ictx = new librbd::ImageCtx("", id, snap_name, io_ctx,
4041 							false);
4042 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
4043 	  tracepoint(librbd, aio_open_image_enter, ictx, ictx->name.c_str(),
4044 	             ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only,
4045 	             comp->pc);
4046 	  ictx->state->open(0, new C_OpenComplete(ictx, get_aio_completion(comp),
4047 	                                          image));
4048 	  tracepoint(librbd, aio_open_image_exit, 0);
4049 	  return 0;
4050 	}
4051 	
4052 	extern "C" int rbd_open_read_only(rados_ioctx_t p, const char *name,
4053 					  rbd_image_t *image, const char *snap_name)
4054 	{
4055 	  librados::IoCtx io_ctx;
4056 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
4057 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
4058 	  librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx,
4059 							true);
4060 	  tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4061 	
4062 	  int r = ictx->state->open(0);
4063 	  if (r >= 0) {
4064 	    *image = (rbd_image_t)ictx;
4065 	  }
4066 	  tracepoint(librbd, open_image_exit, r);
4067 	  return r;
4068 	}
4069 	
4070 	extern "C" int rbd_open_by_id_read_only(rados_ioctx_t p, const char *id,
4071 				                rbd_image_t *image, const char *snap_name)
4072 	{
4073 	  librados::IoCtx io_ctx;
4074 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
4075 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
4076 	  librbd::ImageCtx *ictx = new librbd::ImageCtx("", id, snap_name, io_ctx,
4077 							true);
4078 	  tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(),
4079 	             ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4080 	
4081 	  int r = ictx->state->open(0);
4082 	  if (r < 0) {
4083 	    delete ictx;
4084 	  } else {
4085 	    *image = (rbd_image_t)ictx;
4086 	  }
4087 	  tracepoint(librbd, open_image_exit, r);
4088 	  return r;
4089 	}
4090 	
4091 	extern "C" int rbd_aio_open_read_only(rados_ioctx_t p, const char *name,
4092 					      rbd_image_t *image, const char *snap_name,
4093 					      rbd_completion_t c)
4094 	{
4095 	  librados::IoCtx io_ctx;
4096 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
4097 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
4098 	  librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx,
4099 							true);
4100 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
4101 	  tracepoint(librbd, aio_open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only, comp->pc);
4102 	  ictx->state->open(0, new C_OpenComplete(ictx, get_aio_completion(comp),
4103 	                                          image));
4104 	  tracepoint(librbd, aio_open_image_exit, 0);
4105 	  return 0;
4106 	}
4107 	
4108 	extern "C" int rbd_aio_open_by_id_read_only(rados_ioctx_t p, const char *id,
4109 					            rbd_image_t *image,
4110 	                                            const char *snap_name,
4111 	                                            rbd_completion_t c)
4112 	{
4113 	  librados::IoCtx io_ctx;
4114 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
4115 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
4116 	  librbd::ImageCtx *ictx = new librbd::ImageCtx("", id, snap_name, io_ctx,
4117 							true);
4118 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
4119 	  tracepoint(librbd, aio_open_image_enter, ictx, ictx->name.c_str(),
4120 	             ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only, comp->pc);
4121 	  ictx->state->open(0, new C_OpenComplete(ictx, get_aio_completion(comp),
4122 	                                          image));
4123 	  tracepoint(librbd, aio_open_image_exit, 0);
4124 	  return 0;
4125 	}
4126 	
4127 	extern "C" int rbd_close(rbd_image_t image)
4128 	{
4129 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4130 	  tracepoint(librbd, close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
4131 	
4132 	  int r = ictx->state->close();
4133 	
4134 	  tracepoint(librbd, close_image_exit, r);
4135 	  return r;
4136 	}
4137 	
4138 	extern "C" int rbd_aio_close(rbd_image_t image, rbd_completion_t c)
4139 	{
4140 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4141 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
4142 	  tracepoint(librbd, aio_close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), comp->pc);
4143 	  ictx->state->close(new C_AioCompletion(ictx, librbd::io::AIO_TYPE_CLOSE,
4144 	                                         get_aio_completion(comp)));
4145 	  tracepoint(librbd, aio_close_image_exit, 0);
4146 	  return 0;
4147 	}
4148 	
4149 	extern "C" int rbd_resize(rbd_image_t image, uint64_t size)
4150 	{
4151 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4152 	  tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
4153 	  librbd::NoOpProgressContext prog_ctx;
4154 	  int r = ictx->operations->resize(size, true, prog_ctx);
4155 	  tracepoint(librbd, resize_exit, r);
4156 	  return r;
4157 	}
4158 	
4159 	extern "C" int rbd_resize2(rbd_image_t image, uint64_t size, bool allow_shrink,
4160 						librbd_progress_fn_t cb, void *cbdata)
4161 	{
4162 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4163 	  tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
4164 	  librbd::CProgressContext prog_ctx(cb, cbdata);
4165 	  int r = ictx->operations->resize(size, allow_shrink, prog_ctx);
4166 	  tracepoint(librbd, resize_exit, r);
4167 	  return r;
4168 	}
4169 	
4170 	extern "C" int rbd_resize_with_progress(rbd_image_t image, uint64_t size,
4171 						librbd_progress_fn_t cb, void *cbdata)
4172 	{
4173 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4174 	  tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
4175 	  librbd::CProgressContext prog_ctx(cb, cbdata);
4176 	  int r = ictx->operations->resize(size, true, prog_ctx);
4177 	  tracepoint(librbd, resize_exit, r);
4178 	  return r;
4179 	}
4180 	
4181 	extern "C" int rbd_stat(rbd_image_t image, rbd_image_info_t *info,
4182 				size_t infosize)
4183 	{
4184 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4185 	  tracepoint(librbd, stat_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4186 	  int r = librbd::info(ictx, *info, infosize);
4187 	  tracepoint(librbd, stat_exit, r, info);
4188 	  return r;
4189 	}
4190 	
4191 	extern "C" int rbd_get_old_format(rbd_image_t image, uint8_t *old)
4192 	{
4193 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4194 	  tracepoint(librbd, get_old_format_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4195 	  int r = librbd::get_old_format(ictx, old);
4196 	  tracepoint(librbd, get_old_format_exit, r, *old);
4197 	  return r;
4198 	}
4199 	
4200 	extern "C" int rbd_get_size(rbd_image_t image, uint64_t *size)
4201 	{
4202 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4203 	  tracepoint(librbd, get_size_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4204 	  int r = librbd::get_size(ictx, size);
4205 	  tracepoint(librbd, get_size_exit, r, *size);
4206 	  return r;
4207 	}
4208 	
4209 	extern "C" int rbd_get_features(rbd_image_t image, uint64_t *features)
4210 	{
4211 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4212 	  tracepoint(librbd, get_features_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4213 	  int r = librbd::get_features(ictx, features);
4214 	  tracepoint(librbd, get_features_exit, r, *features);
4215 	  return r;
4216 	}
4217 	
4218 	extern "C" int rbd_update_features(rbd_image_t image, uint64_t features,
4219 	                                  uint8_t enabled)
4220 	{
4221 	  librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
4222 	  bool features_enabled = enabled != 0;
4223 	  tracepoint(librbd, update_features_enter, ictx, features, features_enabled);
4224 	  int r = ictx->operations->update_features(features, features_enabled);
4225 	  tracepoint(librbd, update_features_exit, r);
4226 	  return r;
4227 	}
4228 	
4229 	extern "C" int rbd_get_op_features(rbd_image_t image, uint64_t *op_features)
4230 	{
4231 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4232 	  return librbd::api::Image<>::get_op_features(ictx, op_features);
4233 	}
4234 	
4235 	extern "C" int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit)
4236 	{
4237 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4238 	  tracepoint(librbd, get_stripe_unit_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4239 	  *stripe_unit = ictx->get_stripe_unit();
4240 	  tracepoint(librbd, get_stripe_unit_exit, 0, *stripe_unit);
4241 	  return 0;
4242 	}
4243 	
4244 	extern "C" int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count)
4245 	{
4246 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4247 	  tracepoint(librbd, get_stripe_count_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4248 	  *stripe_count = ictx->get_stripe_count();
4249 	  tracepoint(librbd, get_stripe_count_exit, 0, *stripe_count);
4250 	  return 0;
4251 	}
4252 	
4253 	extern "C"  int rbd_get_create_timestamp(rbd_image_t image,
4254 	                                           struct timespec *timestamp)
4255 	{
4256 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4257 	  tracepoint(librbd, get_create_timestamp_enter, ictx, ictx->name.c_str(),
4258 	             ictx->read_only);
4259 	  utime_t time = ictx->get_create_timestamp();
4260 	  time.to_timespec(timestamp);
4261 	  tracepoint(librbd, get_create_timestamp_exit, 0, timestamp);
4262 	  return 0;
4263 	}
4264 	
4265 	extern "C"  int rbd_get_access_timestamp(rbd_image_t image,
4266 	                                           struct timespec *timestamp)
4267 	{
4268 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4269 	  tracepoint(librbd, get_access_timestamp_enter, ictx, ictx->name.c_str(),
4270 	             ictx->read_only);
4271 	  utime_t time = ictx->get_access_timestamp();
4272 	  time.to_timespec(timestamp);
4273 	  tracepoint(librbd, get_access_timestamp_exit, 0, timestamp);
4274 	  return 0;
4275 	}
4276 	
4277 	extern "C"  int rbd_get_modify_timestamp(rbd_image_t image,
4278 	                                           struct timespec *timestamp)
4279 	{
4280 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4281 	  tracepoint(librbd, get_modify_timestamp_enter, ictx, ictx->name.c_str(),
4282 	             ictx->read_only);
4283 	  utime_t time = ictx->get_modify_timestamp();
4284 	  time.to_timespec(timestamp);
4285 	  tracepoint(librbd, get_modify_timestamp_exit, 0, timestamp);
4286 	  return 0;
4287 	}
4288 	
4289 	
4290 	extern "C" int rbd_get_overlap(rbd_image_t image, uint64_t *overlap)
4291 	{
4292 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4293 	  tracepoint(librbd, get_overlap_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
4294 	  int r = librbd::get_overlap(ictx, overlap);
4295 	  tracepoint(librbd, get_overlap_exit, r, *overlap);
4296 	  return r;
4297 	}
4298 	
4299 	extern "C" int rbd_get_name(rbd_image_t image, char *name, size_t *name_len)
4300 	{
4301 	  librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
4302 	  if (*name_len <= ictx->name.size()) {
4303 	    *name_len = ictx->name.size() + 1;
4304 	    return -ERANGE;
4305 	  }
4306 	
4307 	  strncpy(name, ictx->name.c_str(), ictx->name.size());
4308 	  name[ictx->name.size()] = '\0';
4309 	  *name_len = ictx->name.size() + 1;
4310 	  return 0;
4311 	}
4312 	
4313 	extern "C" int rbd_get_id(rbd_image_t image, char *id, size_t id_len)
4314 	{
4315 	  librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
4316 	  if (ictx->old_format) {
4317 	    return -EINVAL;
4318 	  }
4319 	  if (ictx->id.size() >= id_len) {
4320 	    return -ERANGE;
4321 	  }
4322 	
4323 	  strncpy(id, ictx->id.c_str(), id_len - 1);
4324 	  id[id_len - 1] = '\0';
4325 	  return 0;
4326 	}
4327 	
4328 	extern "C" int rbd_get_block_name_prefix(rbd_image_t image, char *prefix,
4329 	                                         size_t prefix_len)
4330 	{
4331 	  librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
4332 	  if (ictx->object_prefix.size() >= prefix_len) {
4333 	    return -ERANGE;
4334 	  }
4335 	
4336 	  strncpy(prefix, ictx->object_prefix.c_str(), prefix_len - 1);
4337 	  prefix[prefix_len - 1] = '\0';
4338 	  return 0;
4339 	}
4340 	
4341 	extern "C" int64_t rbd_get_data_pool_id(rbd_image_t image)
4342 	{
4343 	  librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
4344 	  return librbd::api::Image<>::get_data_pool_id(ictx);
4345 	}
4346 	
4347 	extern "C" int rbd_get_parent_info(rbd_image_t image,
4348 	                                   char *parent_pool_name, size_t ppool_namelen,
4349 	                                   char *parent_name, size_t pnamelen,
4350 	                                   char *parent_snap_name, size_t psnap_namelen)
4351 	{
4352 	  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4353 	  tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
4354 	             ictx->snap_name.c_str(), ictx->read_only);
4355 	
4356 	  librbd::linked_image_spec_t parent_image;
4357 	  librbd::snap_spec_t parent_snap;
4358 	  int r = librbd::api::Image<>::get_parent(ictx, &parent_image, &parent_snap);
4359 	  if (r >= 0) {
4360 	    if (parent_pool_name) {
4361 	      if (parent_image.pool_name.length() + 1 > ppool_namelen) {
4362 	        r = -ERANGE;
4363 	      } else {
4364 	        strcpy(parent_pool_name, parent_image.pool_name.c_str());
4365 	      }
4366 	    }
4367 	    if (parent_name) {
4368 	      if (parent_image.image_name.length() + 1 > pnamelen) {
4369 	        r = -ERANGE;
4370 	      } else {
4371 	        strcpy(parent_name, parent_image.image_name.c_str());
4372 	      }
4373 	    }
4374 	    if (parent_snap_name) {
4375 	      if (parent_snap.name.length() + 1 > psnap_namelen) {
4376 	        r = -ERANGE;
4377 	      } else {
4378 	        strcpy(parent_snap_name, parent_snap.name.c_str());
4379 	      }
4380 	    }
4381 	  }
4382 	
4383 	  if (r < 0) {
4384 	    tracepoint(librbd, get_parent_info_exit, r, NULL, NULL, NULL, NULL);
4385 	    return r;
4386 	  }
4387 	
4388 	  tracepoint(librbd, get_parent_info_exit, r,
4389 	             parent_image.pool_name.c_str(),
4390 	             parent_image.image_name.c_str(),
4391 	             parent_image.image_id.c_str(),
4392 	             parent_snap.name.c_str());
4393 	  return 0;
4394 	}
4395 	
4396 	extern "C" int rbd_get_parent_info2(rbd_image_t image,
4397 	                                    char *parent_pool_name,
4398 	                                    size_t ppool_namelen,
4399 	                                    char *parent_name, size_t pnamelen,
4400 	                                    char *parent_id, size_t pidlen,
4401 	                                    char *parent_snap_name,
4402 	                                    size_t psnap_namelen)
4403 	{
4404 	  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4405 	  tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
4406 	             ictx->snap_name.c_str(), ictx->read_only);
4407 	
4408 	  librbd::linked_image_spec_t parent_image;
4409 	  librbd::snap_spec_t parent_snap;
4410 	  int r = librbd::api::Image<>::get_parent(ictx, &parent_image, &parent_snap);
4411 	  if (r >= 0) {
4412 	    if (parent_pool_name) {
4413 	      if (parent_image.pool_name.length() + 1 > ppool_namelen) {
4414 	        r = -ERANGE;
4415 	      } else {
4416 	        strcpy(parent_pool_name, parent_image.pool_name.c_str());
4417 	      }
4418 	    }
4419 	    if (parent_name) {
4420 	      if (parent_image.image_name.length() + 1 > pnamelen) {
4421 	        r = -ERANGE;
4422 	      } else {
4423 	        strcpy(parent_name, parent_image.image_name.c_str());
4424 	      }
4425 	    }
4426 	    if (parent_id) {
4427 	      if (parent_image.image_id.length() + 1 > pidlen) {
4428 	        r = -ERANGE;
4429 	      } else {
4430 	        strcpy(parent_id, parent_image.image_id.c_str());
4431 	      }
4432 	  }
4433 	    if (parent_snap_name) {
4434 	      if (parent_snap.name.length() + 1 > psnap_namelen) {
4435 	        r = -ERANGE;
4436 	      } else {
4437 	        strcpy(parent_snap_name, parent_snap.name.c_str());
4438 	      }
4439 	    }
4440 	  }
4441 	
4442 	  if (r < 0) {
4443 	    tracepoint(librbd, get_parent_info_exit, r, NULL, NULL, NULL, NULL);
4444 	    return r;
4445 	  }
4446 	
4447 	  tracepoint(librbd, get_parent_info_exit, r,
4448 	             parent_image.pool_name.c_str(),
4449 	             parent_image.image_name.c_str(),
4450 	             parent_image.image_id.c_str(),
4451 	             parent_snap.name.c_str());
4452 	  return 0;
4453 	}
4454 	
4455 	extern "C" int rbd_get_parent(rbd_image_t image,
4456 	                              rbd_linked_image_spec_t *parent_image,
4457 	                              rbd_snap_spec_t *parent_snap)
4458 	{
4459 	  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4460 	  tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
4461 	             ictx->snap_name.c_str(), ictx->read_only);
4462 	
4463 	  librbd::linked_image_spec_t cpp_parent_image;
4464 	  librbd::snap_spec_t cpp_parent_snap;
4465 	  int r = librbd::api::Image<>::get_parent(ictx, &cpp_parent_image,
4466 	                                           &cpp_parent_snap);
4467 	  if (r < 0) {
4468 	    memset(parent_image, 0, sizeof(rbd_linked_image_spec_t));
4469 	    memset(parent_snap, 0, sizeof(rbd_snap_spec_t));
4470 	  } else {
4471 	    *parent_image = {
4472 	      .pool_id = cpp_parent_image.pool_id,
4473 	      .pool_name = strdup(cpp_parent_image.pool_name.c_str()),
4474 	      .pool_namespace = strdup(cpp_parent_image.pool_namespace.c_str()),
4475 	      .image_id = strdup(cpp_parent_image.image_id.c_str()),
4476 	      .image_name = strdup(cpp_parent_image.image_name.c_str()),
4477 	      .trash = cpp_parent_image.trash};
4478 	    *parent_snap = {
4479 	      .id = cpp_parent_snap.id,
4480 	      .namespace_type = cpp_parent_snap.namespace_type,
4481 	      .name = strdup(cpp_parent_snap.name.c_str())};
4482 	  }
4483 	
4484 	  tracepoint(librbd, get_parent_info_exit, r,
4485 	             parent_image->pool_name,
4486 	             parent_image->image_name,
4487 	             parent_image->image_id,
4488 	             parent_snap->name);
4489 	  return r;
4490 	}
4491 	
4492 	extern "C" int rbd_get_flags(rbd_image_t image, uint64_t *flags)
4493 	{
4494 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4495 	  tracepoint(librbd, get_flags_enter, ictx);
4496 	  int r = librbd::get_flags(ictx, flags);
4497 	  tracepoint(librbd, get_flags_exit, ictx, r, *flags);
4498 	  return r;
4499 	}
4500 	
4501 	extern "C" int rbd_get_group(rbd_image_t image, rbd_group_info_t *group_info,
4502 	                             size_t group_info_size)
4503 	{
4504 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4505 	  tracepoint(librbd, image_get_group_enter, ictx->name.c_str());
4506 	
4507 	  if (group_info_size != sizeof(rbd_group_info_t)) {
4508 	    tracepoint(librbd, image_get_group_exit, -ERANGE);
4509 	    return -ERANGE;
4510 	  }
4511 	
4512 	  librbd::group_info_t cpp_group_info;
4513 	  int r = librbd::api::Group<>::image_get_group(ictx, &cpp_group_info);
4514 	  if (r >= 0) {
4515 	    group_info_cpp_to_c(cpp_group_info, group_info);
4516 	  } else {
4517 	    group_info->name = NULL;
4518 	  }
4519 	
4520 	  tracepoint(librbd, image_get_group_exit, r);
4521 	  return r;
4522 	}
4523 	
4524 	extern "C" int rbd_set_image_notification(rbd_image_t image, int fd, int type)
4525 	{
4526 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4527 	  tracepoint(librbd, set_image_notification_enter, ictx, fd, type);
4528 	  int r = librbd::set_image_notification(ictx, fd, type);
4529 	  tracepoint(librbd, set_image_notification_exit, ictx, r);
4530 	  return r;
4531 	}
4532 	
4533 	extern "C" int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner)
4534 	{
4535 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4536 	  tracepoint(librbd, is_exclusive_lock_owner_enter, ictx);
4537 	  bool owner;
4538 	  int r = librbd::is_exclusive_lock_owner(ictx, &owner);
4539 	  *is_owner = owner ? 1 : 0;
4540 	  tracepoint(librbd, is_exclusive_lock_owner_exit, ictx, r, *is_owner);
4541 	  return r;
4542 	}
4543 	
4544 	extern "C" int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode)
4545 	{
4546 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4547 	  tracepoint(librbd, lock_acquire_enter, ictx, lock_mode);
4548 	  int r = librbd::lock_acquire(ictx, lock_mode);
4549 	  tracepoint(librbd, lock_acquire_exit, ictx, r);
4550 	  return r;
4551 	}
4552 	
4553 	extern "C" int rbd_lock_release(rbd_image_t image)
4554 	{
4555 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4556 	  tracepoint(librbd, lock_release_enter, ictx);
4557 	  int r = librbd::lock_release(ictx);
4558 	  tracepoint(librbd, lock_release_exit, ictx, r);
4559 	  return r;
4560 	}
4561 	
4562 	extern "C" int rbd_lock_get_owners(rbd_image_t image,
4563 	                                   rbd_lock_mode_t *lock_mode,
4564 	                                   char **lock_owners,
4565 	                                   size_t *max_lock_owners)
4566 	{
4567 	  librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4568 	  tracepoint(librbd, lock_get_owners_enter, ictx);
4569 	  memset(lock_owners, 0, sizeof(*lock_owners) * *max_lock_owners);
4570 	  std::list<std::string> lock_owner_list;
4571 	  int r = librbd::lock_get_owners(ictx, lock_mode, &lock_owner_list);
4572 	  if (r >= 0) {
4573 	    if (*max_lock_owners >= lock_owner_list.size()) {
4574 	      *max_lock_owners = 0;
4575 	      for (auto &lock_owner : lock_owner_list) {
4576 	        lock_owners[(*max_lock_owners)++] = strdup(lock_owner.c_str());
4577 	      }
4578 	    } else {
4579 	      *max_lock_owners = lock_owner_list.size();
4580 	      r = -ERANGE;
4581 	    }
4582 	  }
4583 	  tracepoint(librbd, lock_get_owners_exit, ictx, r);
4584 	  return r;
4585 	}
4586 	
4587 	extern "C" void rbd_lock_get_owners_cleanup(char **lock_owners,
4588 	                                            size_t lock_owner_count)
4589 	{
4590 	  for (size_t i = 0; i < lock_owner_count; ++i) {
4591 	    free(lock_owners[i]);
4592 	  }
4593 	}
4594 	
4595 	extern "C" int rbd_lock_break(rbd_image_t image, rbd_lock_mode_t lock_mode,
4596 	                              const char *lock_owner)
4597 	{
4598 	  librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4599 	  tracepoint(librbd, lock_break_enter, ictx, lock_mode, lock_owner);
4600 	  int r = librbd::lock_break(ictx, lock_mode, lock_owner);
4601 	  tracepoint(librbd, lock_break_exit, ictx, r);
4602 	  return r;
4603 	}
4604 	
4605 	extern "C" int rbd_rebuild_object_map(rbd_image_t image,
4606 	                                      librbd_progress_fn_t cb, void *cbdata)
4607 	{
4608 	  librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4609 	  librbd::CProgressContext prog_ctx(cb, cbdata);
4610 	  return ictx->operations->rebuild_object_map(prog_ctx);
4611 	}
4612 	
4613 	/* snapshots */
4614 	extern "C" int rbd_snap_create(rbd_image_t image, const char *snap_name)
4615 	{
4616 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4617 	  tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
4618 	  int r = ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
4619 						snap_name);
4620 	  tracepoint(librbd, snap_create_exit, r);
4621 	  return r;
4622 	}
4623 	
4624 	extern "C" int rbd_snap_rename(rbd_image_t image, const char *srcname, const char *dstname)
4625 	{
4626 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4627 	  tracepoint(librbd, snap_rename_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, srcname, dstname);
4628 	  int r = ictx->operations->snap_rename(srcname, dstname);
4629 	  tracepoint(librbd, snap_rename_exit, r);
4630 	  return r;
4631 	}
4632 	
4633 	extern "C" int rbd_snap_remove(rbd_image_t image, const char *snap_name)
4634 	{
4635 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4636 	  tracepoint(librbd, snap_remove_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
4637 	  librbd::NoOpProgressContext prog_ctx;
4638 	  int r = librbd::snap_remove(ictx, snap_name, 0, prog_ctx);
4639 	  tracepoint(librbd, snap_remove_exit, r);
4640 	  return r;
4641 	}
4642 	
4643 	extern "C" int rbd_snap_remove2(rbd_image_t image, const char *snap_name, uint32_t flags,
4644 					librbd_progress_fn_t cb, void *cbdata)
4645 	{
4646 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4647 	  tracepoint(librbd, snap_remove2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name, flags);
4648 	  librbd::CProgressContext prog_ctx(cb, cbdata);
4649 	  int r = librbd::snap_remove(ictx, snap_name, flags, prog_ctx);
4650 	  tracepoint(librbd, snap_remove_exit, r);
4651 	  return r;
4652 	}
4653 	
4654 	extern "C" int rbd_snap_remove_by_id(rbd_image_t image, uint64_t snap_id)
4655 	{
4656 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4657 	  return librbd::api::Snapshot<>::remove(ictx, snap_id);
4658 	}
4659 	
4660 	extern "C" int rbd_snap_rollback(rbd_image_t image, const char *snap_name)
4661 	{
4662 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4663 	  tracepoint(librbd, snap_rollback_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
4664 	  librbd::NoOpProgressContext prog_ctx;
4665 	  int r = ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(), snap_name, prog_ctx);
4666 	  tracepoint(librbd, snap_rollback_exit, r);
4667 	  return r;
4668 	}
4669 	
4670 	extern "C" int rbd_snap_rollback_with_progress(rbd_image_t image,
4671 						       const char *snap_name,
4672 						       librbd_progress_fn_t cb,
4673 						       void *cbdata)
4674 	{
4675 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4676 	  tracepoint(librbd, snap_rollback_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
4677 	  librbd::CProgressContext prog_ctx(cb, cbdata);
4678 	  int r = ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(), snap_name, prog_ctx);
4679 	  tracepoint(librbd, snap_rollback_exit, r);
4680 	  return r;
4681 	}
4682 	
4683 	extern "C" int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
4684 				     int *max_snaps)
4685 	{
4686 	  vector<librbd::snap_info_t> cpp_snaps;
4687 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4688 	  tracepoint(librbd, snap_list_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snaps);
4689 	
4690 	  if (!max_snaps) {
4691 	    tracepoint(librbd, snap_list_exit, -EINVAL, 0);
4692 	    return -EINVAL;
4693 	  }
4694 	  memset(snaps, 0, sizeof(*snaps) * *max_snaps);
4695 	
4696 	  int r = librbd::snap_list(ictx, cpp_snaps);
4697 	  if (r == -ENOENT) {
4698 	    tracepoint(librbd, snap_list_exit, 0, *max_snaps);
4699 	    return 0;
4700 	  }
4701 	  if (r < 0) {
4702 	    tracepoint(librbd, snap_list_exit, r, *max_snaps);
4703 	    return r;
4704 	  }
4705 	  if (*max_snaps < (int)cpp_snaps.size() + 1) {
4706 	    *max_snaps = (int)cpp_snaps.size() + 1;
4707 	    tracepoint(librbd, snap_list_exit, -ERANGE, *max_snaps);
4708 	    return -ERANGE;
4709 	  }
4710 	
4711 	  int i;
4712 	
4713 	  for (i = 0; i < (int)cpp_snaps.size(); i++) {
4714 	    snaps[i].id = cpp_snaps[i].id;
4715 	    snaps[i].size = cpp_snaps[i].size;
4716 	    snaps[i].name = strdup(cpp_snaps[i].name.c_str());
4717 	    if (!snaps[i].name) {
4718 	      for (int j = 0; j < i; j++)
4719 		free((void *)snaps[j].name);
4720 	      tracepoint(librbd, snap_list_exit, -ENOMEM, *max_snaps);
4721 	      return -ENOMEM;
4722 	    }
4723 	    tracepoint(librbd, snap_list_entry, snaps[i].id, snaps[i].size, snaps[i].name);
4724 	  }
4725 	  snaps[i].id = 0;
4726 	  snaps[i].size = 0;
4727 	  snaps[i].name = NULL;
4728 	
4729 	  r = (int)cpp_snaps.size();
4730 	  tracepoint(librbd, snap_list_exit, r, *max_snaps);
4731 	  return r;
4732 	}
4733 	
4734 	extern "C" void rbd_snap_list_end(rbd_snap_info_t *snaps)
4735 	{
4736 	  tracepoint(librbd, snap_list_end_enter, snaps);
4737 	  while (snaps->name) {
4738 	    free((void *)snaps->name);
4739 	    snaps++;
4740 	  }
4741 	  tracepoint(librbd, snap_list_end_exit);
4742 	}
4743 	
4744 	extern "C" int rbd_snap_protect(rbd_image_t image, const char *snap_name)
4745 	{
4746 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4747 	  tracepoint(librbd, snap_protect_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
4748 	  int r = ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(), snap_name);
4749 	  tracepoint(librbd, snap_protect_exit, r);
4750 	  return r;
4751 	}
4752 	
4753 	extern "C" int rbd_snap_unprotect(rbd_image_t image, const char *snap_name)
4754 	{
4755 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4756 	  tracepoint(librbd, snap_unprotect_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
4757 	  int r = ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(), snap_name);
4758 	  tracepoint(librbd, snap_unprotect_exit, r);
4759 	  return r;
4760 	}
4761 	
4762 	extern "C" int rbd_snap_is_protected(rbd_image_t image, const char *snap_name,
4763 					     int *is_protected)
4764 	{
4765 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4766 	  tracepoint(librbd, snap_is_protected_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
4767 	  bool protected_snap;
4768 	  int r = librbd::snap_is_protected(ictx, snap_name, &protected_snap);
4769 	  if (r < 0) {
4770 	    tracepoint(librbd, snap_is_protected_exit, r, *is_protected ? 1 : 0);
4771 	    return r;
4772 	  }
4773 	  *is_protected = protected_snap ? 1 : 0;
4774 	  tracepoint(librbd, snap_is_protected_exit, 0, *is_protected ? 1 : 0);
4775 	  return 0;
4776 	}
4777 	
4778 	extern "C" int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
4779 	{
4780 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4781 	  tracepoint(librbd, snap_get_limit_enter, ictx, ictx->name.c_str());
4782 	  int r = librbd::snap_get_limit(ictx, limit);
4783 	  tracepoint(librbd, snap_get_limit_exit, r, *limit);
4784 	  return r;
4785 	}
4786 	
4787 	extern "C" int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, struct timespec *timestamp)
4788 	{
4789 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4790 	  tracepoint(librbd, snap_get_timestamp_enter, ictx, ictx->name.c_str());
4791 	  int r = librbd::snap_get_timestamp(ictx, snap_id, timestamp);
4792 	  tracepoint(librbd, snap_get_timestamp_exit, r);
4793 	  return r;
4794 	}
4795 	
4796 	extern "C" int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
4797 	{
4798 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4799 	  tracepoint(librbd, snap_set_limit_enter, ictx, ictx->name.c_str(), limit);
4800 	  int r = librbd::snap_set_limit(ictx, limit);
4801 	  tracepoint(librbd, snap_set_limit_exit, r);
4802 	  return r;
4803 	}
4804 	
4805 	extern "C" int rbd_snap_set(rbd_image_t image, const char *snap_name)
4806 	{
4807 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4808 	  tracepoint(librbd, snap_set_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
4809 	  int r = librbd::api::Image<>::snap_set(
4810 	    ictx, cls::rbd::UserSnapshotNamespace(), snap_name);
4811 	  tracepoint(librbd, snap_set_exit, r);
4812 	  return r;
4813 	}
4814 	
4815 	extern "C" int rbd_snap_set_by_id(rbd_image_t image, uint64_t snap_id)
4816 	{
4817 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
4818 	  return librbd::api::Image<>::snap_set(ictx, snap_id);
4819 	}
4820 	
4821 	extern "C" ssize_t rbd_list_children(rbd_image_t image, char *pools,
4822 					     size_t *pools_len, char *images,
4823 					     size_t *images_len)
4824 	{
4825 	  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4826 	  tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(),
4827 	             ictx->snap_name.c_str(), ictx->read_only);
4828 	
4829 	  std::vector<librbd::linked_image_spec_t> cpp_images;
4830 	  int r = librbd::api::Image<>::list_children(ictx, &cpp_images);
4831 	  if (r < 0) {
4832 	    tracepoint(librbd, list_children_exit, r);
4833 	    return r;
4834 	  }
4835 	
4836 	  std::set<std::pair<std::string, std::string>> image_set;
4837 	  for (auto& image : cpp_images) {
4838 	    if (!image.trash) {
4839 	      image_set.insert({image.pool_name, image.image_name});
4840 	    }
4841 	  }
4842 	
4843 	  size_t pools_total = 0;
4844 	  size_t images_total = 0;
4845 	  for (auto it : image_set) {
4846 	    pools_total += it.first.length() + 1;
4847 	    images_total += it.second.length() + 1;
4848 	  }
4849 	
4850 	  bool too_short = false;
4851 	  if (pools_total > *pools_len)
4852 	    too_short = true;
4853 	  if (images_total > *images_len)
4854 	    too_short = true;
4855 	  *pools_len = pools_total;
4856 	  *images_len = images_total;
4857 	  if (too_short) {
4858 	    tracepoint(librbd, list_children_exit, -ERANGE);
4859 	    return -ERANGE;
4860 	  }
4861 	
4862 	  char *pools_p = pools;
4863 	  char *images_p = images;
4864 	  for (auto it : image_set) {
4865 	    const char* pool = it.first.c_str();
4866 	    strcpy(pools_p, pool);
4867 	    pools_p += it.first.length() + 1;
4868 	    const char* image = it.second.c_str();
4869 	    strcpy(images_p, image);
4870 	    images_p += it.second.length() + 1;
4871 	    tracepoint(librbd, list_children_entry, pool, image);
4872 	  }
4873 	
4874 	  ssize_t ret = image_set.size();
4875 	  tracepoint(librbd, list_children_exit, ret);
4876 	  return ret;
4877 	}
4878 	
4879 	extern "C" int rbd_list_children2(rbd_image_t image,
4880 	                                  rbd_child_info_t *children,
4881 		                          int *max_children)
4882 	{
4883 	  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4884 	  tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(),
4885 	             ictx->snap_name.c_str(), ictx->read_only);
4886 	  memset(children, 0, sizeof(*children) * *max_children);
4887 	
4888 	  if (!max_children) {
4889 	    tracepoint(librbd, list_children_exit, -EINVAL);
4890 	    return -EINVAL;
4891 	  }
4892 	
4893 	  std::vector<librbd::linked_image_spec_t> cpp_children;
4894 	  int r = librbd::api::Image<>::list_children(ictx, &cpp_children);
4895 	  if (r < 0) {
4896 	    tracepoint(librbd, list_children_exit, r);
4897 	    return r;
4898 	  }
4899 	
4900 	  if (*max_children < (int)cpp_children.size() + 1) {
4901 	    *max_children = (int)cpp_children.size() + 1;
4902 	    tracepoint(librbd, list_children_exit, *max_children);
4903 	    return -ERANGE;
4904 	  }
4905 	
4906 	  int i;
4907 	  for (i = 0; i < (int)cpp_children.size(); i++) {
4908 	    children[i].pool_name = strdup(cpp_children[i].pool_name.c_str());
4909 	    children[i].image_name = strdup(cpp_children[i].image_name.c_str());
4910 	    children[i].image_id = strdup(cpp_children[i].image_id.c_str());
4911 	    children[i].trash = cpp_children[i].trash;
4912 	    tracepoint(librbd, list_children_entry, children[i].pool_name,
4913 	               children[i].image_name);
4914 	  }
4915 	  children[i].pool_name = NULL;
4916 	  children[i].image_name = NULL;
4917 	  children[i].image_id = NULL;
4918 	
4919 	  r = (int)cpp_children.size();
4920 	  tracepoint(librbd, list_children_exit, *max_children);
4921 	  return r;
4922 	}
4923 	
4924 	extern "C" void rbd_list_child_cleanup(rbd_child_info_t *child)
4925 	{
4926 	  free((void *)child->pool_name);
4927 	  free((void *)child->image_name);
4928 	  free((void *)child->image_id);
4929 	}
4930 	
4931 	extern "C" void rbd_list_children_cleanup(rbd_child_info_t *children,
4932 	                                          size_t num_children)
4933 	{
4934 	  for (size_t i=0; i < num_children; i++) {
4935 	    free((void *)children[i].pool_name);
4936 	    free((void *)children[i].image_name);
4937 	    free((void *)children[i].image_id);
4938 	  }
4939 	}
4940 	
4941 	extern "C" int rbd_list_children3(rbd_image_t image,
4942 	                                    rbd_linked_image_spec_t *images,
4943 	                                    size_t *max_images)
4944 	{
4945 	  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4946 	  tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(),
4947 	             ictx->snap_name.c_str(), ictx->read_only);
4948 	  memset(images, 0, sizeof(*images) * *max_images);
4949 	
4950 	  std::vector<librbd::linked_image_spec_t> cpp_children;
4951 	  int r = librbd::api::Image<>::list_children(ictx, &cpp_children);
4952 	  if (r < 0) {
4953 	    tracepoint(librbd, list_children_exit, r);
4954 	    return r;
4955 	  }
4956 	
4957 	  if (*max_images < cpp_children.size()) {
4958 	    *max_images = cpp_children.size();
4959 	    return -ERANGE;
4960 	  }
4961 	
4962 	  *max_images = cpp_children.size();
4963 	  for (size_t idx = 0; idx < cpp_children.size(); ++idx) {
4964 	    images[idx] = {
4965 	      .pool_id = cpp_children[idx].pool_id,
4966 	      .pool_name = strdup(cpp_children[idx].pool_name.c_str()),
4967 	      .pool_namespace = strdup(cpp_children[idx].pool_namespace.c_str()),
4968 	      .image_id = strdup(cpp_children[idx].image_id.c_str()),
4969 	      .image_name = strdup(cpp_children[idx].image_name.c_str()),
4970 	      .trash = cpp_children[idx].trash};
4971 	    tracepoint(librbd, list_children_entry, images[idx].pool_name,
4972 	               images[idx].image_name);
4973 	  }
4974 	  return 0;
4975 	}
4976 	
4977 	extern "C" int rbd_list_descendants(rbd_image_t image,
4978 	                                    rbd_linked_image_spec_t *images,
4979 	                                    size_t *max_images)
4980 	{
4981 	  auto ictx = reinterpret_cast<librbd::ImageCtx*>(image);
4982 	  memset(images, 0, sizeof(*images) * *max_images);
4983 	
4984 	  std::vector<librbd::linked_image_spec_t> cpp_children;
4985 	  int r = librbd::api::Image<>::list_descendants(ictx, {}, &cpp_children);
4986 	  if (r < 0) {
4987 	    return r;
4988 	  }
4989 	
4990 	  if (*max_images < cpp_children.size()) {
4991 	    *max_images = cpp_children.size();
4992 	    return -ERANGE;
4993 	  }
4994 	
4995 	  *max_images = cpp_children.size();
4996 	  for (size_t idx = 0; idx < cpp_children.size(); ++idx) {
4997 	    images[idx] = {
4998 	      .pool_id = cpp_children[idx].pool_id,
4999 	      .pool_name = strdup(cpp_children[idx].pool_name.c_str()),
5000 	      .pool_namespace = strdup(cpp_children[idx].pool_namespace.c_str()),
5001 	      .image_id = strdup(cpp_children[idx].image_id.c_str()),
5002 	      .image_name = strdup(cpp_children[idx].image_name.c_str()),
5003 	      .trash = cpp_children[idx].trash};
5004 	  }
5005 	  return 0;
5006 	}
5007 	
5008 	extern "C" ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
5009 					    char *tag, size_t *tag_len,
5010 					    char *clients, size_t *clients_len,
5011 					    char *cookies, size_t *cookies_len,
5012 					    char *addrs, size_t *addrs_len)
5013 	{
5014 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5015 	  tracepoint(librbd, list_lockers_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
5016 	  std::list<librbd::locker_t> lockers;
5017 	  bool exclusive_bool;
5018 	  string tag_str;
5019 	
5020 	  int r = list_lockers(ictx, &lockers, &exclusive_bool, &tag_str);
5021 	  if (r < 0) {
5022 	    tracepoint(librbd, list_lockers_exit, r);
5023 	    return r;
5024 	  }
5025 	
5026 	  ldout(ictx->cct, 20) << "list_lockers r = " << r << " lockers.size() = " << lockers.size() << dendl;
5027 	
5028 	  *exclusive = (int)exclusive_bool;
5029 	  size_t clients_total = 0;
5030 	  size_t cookies_total = 0;
5031 	  size_t addrs_total = 0;
5032 	  for (list<librbd::locker_t>::const_iterator it = lockers.begin();
5033 	       it != lockers.end(); ++it) {
5034 	    clients_total += it->client.length() + 1;
5035 	    cookies_total += it->cookie.length() + 1;
5036 	    addrs_total += it->address.length() + 1;
5037 	  }
5038 	
5039 	  bool too_short = ((clients_total > *clients_len) ||
5040 			    (cookies_total > *cookies_len) ||
5041 			    (addrs_total > *addrs_len) ||
5042 			    (tag_str.length() + 1 > *tag_len));
5043 	  *clients_len = clients_total;
5044 	  *cookies_len = cookies_total;
5045 	  *addrs_len = addrs_total;
5046 	  *tag_len = tag_str.length() + 1;
5047 	  if (too_short) {
5048 	    tracepoint(librbd, list_lockers_exit, -ERANGE);
5049 	    return -ERANGE;
5050 	  }
5051 	
5052 	  strcpy(tag, tag_str.c_str());
5053 	  char *clients_p = clients;
5054 	  char *cookies_p = cookies;
5055 	  char *addrs_p = addrs;
5056 	  for (list<librbd::locker_t>::const_iterator it = lockers.begin();
5057 	       it != lockers.end(); ++it) {
5058 	    const char* client = it->client.c_str();
5059 	    strcpy(clients_p, client);
5060 	    clients_p += it->client.length() + 1;
5061 	    const char* cookie = it->cookie.c_str();
5062 	    strcpy(cookies_p, cookie);
5063 	    cookies_p += it->cookie.length() + 1;
5064 	    const char* address = it->address.c_str();
5065 	    strcpy(addrs_p, address);
5066 	    addrs_p += it->address.length() + 1;
5067 	    tracepoint(librbd, list_lockers_entry, client, cookie, address);
5068 	  }
5069 	
5070 	  ssize_t ret = lockers.size();
5071 	  tracepoint(librbd, list_lockers_exit, ret);
5072 	  return ret;
5073 	}
5074 	
5075 	extern "C" int rbd_lock_exclusive(rbd_image_t image, const char *cookie)
5076 	{
5077 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5078 	  tracepoint(librbd, lock_exclusive_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie);
5079 	  int r = librbd::lock(ictx, true, cookie ? cookie : "", "");
5080 	  tracepoint(librbd, lock_exclusive_exit, r);
5081 	  return r;
5082 	}
5083 	
5084 	extern "C" int rbd_lock_shared(rbd_image_t image, const char *cookie,
5085 				       const char *tag)
5086 	{
5087 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5088 	  tracepoint(librbd, lock_shared_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie, tag);
5089 	  int r = librbd::lock(ictx, false, cookie ? cookie : "", tag ? tag : "");
5090 	  tracepoint(librbd, lock_shared_exit, r);
5091 	  return r;
5092 	}
5093 	
5094 	extern "C" int rbd_unlock(rbd_image_t image, const char *cookie)
5095 	{
5096 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5097 	  tracepoint(librbd, unlock_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie);
5098 	  int r = librbd::unlock(ictx, cookie ? cookie : "");
5099 	  tracepoint(librbd, unlock_exit, r);
5100 	  return r;
5101 	}
5102 	
5103 	extern "C" int rbd_break_lock(rbd_image_t image, const char *client,
5104 				      const char *cookie)
5105 	{
5106 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5107 	  tracepoint(librbd, break_lock_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, client, cookie);
5108 	  int r = librbd::break_lock(ictx, client, cookie ? cookie : "");
5109 	  tracepoint(librbd, break_lock_exit, r);
5110 	  return r;
5111 	}
5112 	
5113 	/* I/O */
5114 	extern "C" ssize_t rbd_read(rbd_image_t image, uint64_t ofs, size_t len,
5115 				    char *buf)
5116 	{
5117 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5118 	  tracepoint(librbd, read_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
5119 	  int r = ictx->io_work_queue->read(ofs, len, librbd::io::ReadResult{buf, len},
5120 	                                    0);
5121 	  tracepoint(librbd, read_exit, r);
5122 	  return r;
5123 	}
5124 	
5125 	extern "C" ssize_t rbd_read2(rbd_image_t image, uint64_t ofs, size_t len,
5126 				      char *buf, int op_flags)
5127 	{
5128 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5129 	  tracepoint(librbd, read2_enter, ictx, ictx->name.c_str(),
5130 		      ictx->snap_name.c_str(), ictx->read_only, ofs, len, op_flags);
5131 	  int r = ictx->io_work_queue->read(ofs, len, librbd::io::ReadResult{buf, len},
5132 	                                    op_flags);
5133 	  tracepoint(librbd, read_exit, r);
5134 	  return r;
5135 	}
5136 	
5137 	
5138 	extern "C" int64_t rbd_read_iterate(rbd_image_t image, uint64_t ofs, size_t len,
5139 					    int (*cb)(uint64_t, size_t, const char *, void *),
5140 					    void *arg)
5141 	{
5142 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5143 	  tracepoint(librbd, read_iterate_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
5144 	  int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg);
5145 	  tracepoint(librbd, read_iterate_exit, r);
5146 	  return r;
5147 	}
5148 	
5149 	extern "C" int rbd_read_iterate2(rbd_image_t image, uint64_t ofs, uint64_t len,
5150 					 int (*cb)(uint64_t, size_t, const char *, void *),
5151 					 void *arg)
5152 	{
5153 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5154 	  tracepoint(librbd, read_iterate2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
5155 	  int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg);
5156 	  if (r > 0)
5157 	    r = 0;
5158 	  tracepoint(librbd, read_iterate2_exit, r);
5159 	  return (int)r;
5160 	}
5161 	
5162 	extern "C" int rbd_diff_iterate(rbd_image_t image,
5163 					const char *fromsnapname,
5164 					uint64_t ofs, uint64_t len,
5165 					int (*cb)(uint64_t, size_t, int, void *),
5166 					void *arg)
5167 	{
5168 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5169 	  tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(),
5170 	             ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len,
5171 	             true, false);
5172 	  int r = librbd::api::DiffIterate<>::diff_iterate(ictx,
5173 							   cls::rbd::UserSnapshotNamespace(),
5174 							   fromsnapname, ofs, len,
5175 	                                                   true, false, cb, arg);
5176 	  tracepoint(librbd, diff_iterate_exit, r);
5177 	  return r;
5178 	}
5179 	
5180 	extern "C" int rbd_diff_iterate2(rbd_image_t image, const char *fromsnapname,
5181 	                                uint64_t ofs, uint64_t len,
5182 	                                uint8_t include_parent, uint8_t whole_object,
5183 	                                int (*cb)(uint64_t, size_t, int, void *),
5184 	                                void *arg)
5185 	{
5186 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5187 	  tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(),
5188 	            ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len,
5189 	            include_parent != 0, whole_object != 0);
5190 	  int r = librbd::api::DiffIterate<>::diff_iterate(ictx,
5191 							   cls::rbd::UserSnapshotNamespace(),
5192 							   fromsnapname, ofs, len,
5193 	                                                   include_parent, whole_object,
5194 	                                                   cb, arg);
5195 	  tracepoint(librbd, diff_iterate_exit, r);
5196 	  return r;
5197 	}
5198 	
5199 	extern "C" ssize_t rbd_write(rbd_image_t image, uint64_t ofs, size_t len,
5200 				     const char *buf)
5201 	{
5202 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5203 	  tracepoint(librbd, write_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len, buf);
5204 	
5205 	  bufferlist bl;
5206 	  bl.push_back(create_write_raw(ictx, buf, len, nullptr));
5207 	  int r = ictx->io_work_queue->write(ofs, len, std::move(bl), 0);
5208 	  tracepoint(librbd, write_exit, r);
5209 	  return r;
5210 	}
5211 	
5212 	extern "C" ssize_t rbd_write2(rbd_image_t image, uint64_t ofs, size_t len,
5213 				      const char *buf, int op_flags)
5214 	{
5215 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5216 	  tracepoint(librbd, write2_enter, ictx, ictx->name.c_str(),
5217 		      ictx->snap_name.c_str(), ictx->read_only, ofs, len, buf, op_flags);
5218 	
5219 	  bufferlist bl;
5220 	  bl.push_back(create_write_raw(ictx, buf, len, nullptr));
5221 	  int r = ictx->io_work_queue->write(ofs, len, std::move(bl), op_flags);
5222 	  tracepoint(librbd, write_exit, r);
5223 	  return r;
5224 	}
5225 	
5226 	
5227 	extern "C" int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len)
5228 	{
5229 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5230 	  tracepoint(librbd, discard_enter, ictx, ictx->name.c_str(),
5231 	             ictx->snap_name.c_str(), ictx->read_only, ofs, len);
5232 	  if (len > static_cast<uint64_t>(std::numeric_limits<int>::max())) {
5233 	    tracepoint(librbd, discard_exit, -EINVAL);
5234 	    return -EINVAL;
5235 	  }
5236 	
5237 	  int r = ictx->io_work_queue->discard(
5238 	    ofs, len, ictx->discard_granularity_bytes);
5239 	  tracepoint(librbd, discard_exit, r);
5240 	  return r;
5241 	}
5242 	
5243 	extern "C" ssize_t rbd_writesame(rbd_image_t image, uint64_t ofs, size_t len,
5244 	                                 const char *buf, size_t data_len, int op_flags)
5245 	{
5246 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5247 	  tracepoint(librbd, writesame_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
5248 	             ictx->read_only, ofs, len, data_len == 0 ? NULL : buf, data_len, op_flags);
5249 	
5250 	  if (data_len == 0 || len % data_len ||
5251 	      len > static_cast<uint64_t>(std::numeric_limits<int>::max())) {
5252 	    tracepoint(librbd, writesame_exit, -EINVAL);
5253 	    return -EINVAL;
5254 	  }
5255 	
5256 	  bool discard_zero = ictx->config.get_val<bool>("rbd_discard_on_zeroed_write_same");
5257 	  if (discard_zero && mem_is_zero(buf, data_len)) {
5258 	    int r = ictx->io_work_queue->discard(ofs, len, 0);
5259 	    tracepoint(librbd, writesame_exit, r);
5260 	    return r;
5261 	  }
5262 	
5263 	  bufferlist bl;
5264 	  bl.push_back(create_write_raw(ictx, buf, data_len, nullptr));
5265 	  int r = ictx->io_work_queue->writesame(ofs, len, std::move(bl), op_flags);
5266 	  tracepoint(librbd, writesame_exit, r);
5267 	  return r;
5268 	}
5269 	
5270 	extern "C" ssize_t rbd_compare_and_write(rbd_image_t image,
5271 	                                         uint64_t ofs, size_t len,
5272 	                                         const char *cmp_buf,
5273 	                                         const char *buf,
5274 	                                         uint64_t *mismatch_off,
5275 	                                         int op_flags)
5276 	{
5277 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5278 	  tracepoint(librbd, compare_and_write_enter, ictx, ictx->name.c_str(),
5279 	             ictx->snap_name.c_str(), ictx->read_only, ofs,
5280 	             len, cmp_buf, buf, op_flags);
5281 	
5282 	  bufferlist cmp_bl;
5283 	  cmp_bl.push_back(create_write_raw(ictx, cmp_buf, len, nullptr));
5284 	  bufferlist bl;
5285 	  bl.push_back(create_write_raw(ictx, buf, len, nullptr));
5286 	
5287 	  int r = ictx->io_work_queue->compare_and_write(ofs, len, std::move(cmp_bl),
5288 	                                                 std::move(bl), mismatch_off,
5289 	                                                 op_flags);
5290 	  tracepoint(librbd, compare_and_write_exit, r);
5291 	  return r;
5292 	}
5293 	
5294 	extern "C" int rbd_aio_create_completion(void *cb_arg,
5295 						 rbd_callback_t complete_cb,
5296 						 rbd_completion_t *c)
5297 	{
5298 	  librbd::RBD::AioCompletion *rbd_comp =
5299 	    new librbd::RBD::AioCompletion(cb_arg, complete_cb);
5300 	  *c = (rbd_completion_t) rbd_comp;
5301 	  return 0;
5302 	}
5303 	
5304 	extern "C" int rbd_aio_write(rbd_image_t image, uint64_t off, size_t len,
5305 				     const char *buf, rbd_completion_t c)
5306 	{
5307 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5308 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5309 	  tracepoint(librbd, aio_write_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, buf, comp->pc);
5310 	
5311 	  auto aio_completion = get_aio_completion(comp);
5312 	  bufferlist bl;
5313 	  bl.push_back(create_write_raw(ictx, buf, len, aio_completion));
5314 	  ictx->io_work_queue->aio_write(aio_completion, off, len, std::move(bl), 0);
5315 	  tracepoint(librbd, aio_write_exit, 0);
5316 	  return 0;
5317 	}
5318 	
5319 	extern "C" int rbd_aio_write2(rbd_image_t image, uint64_t off, size_t len,
5320 				      const char *buf, rbd_completion_t c, int op_flags)
5321 	{
5322 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5323 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5324 	  tracepoint(librbd, aio_write2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
5325 		      ictx->read_only, off, len, buf, comp->pc, op_flags);
5326 	
5327 	  auto aio_completion = get_aio_completion(comp);
5328 	  bufferlist bl;
5329 	  bl.push_back(create_write_raw(ictx, buf, len, aio_completion));
5330 	  ictx->io_work_queue->aio_write(aio_completion, off, len, std::move(bl),
5331 	                                 op_flags);
5332 	  tracepoint(librbd, aio_write_exit, 0);
5333 	  return 0;
5334 	}
5335 	
5336 	extern "C" int rbd_aio_writev(rbd_image_t image, const struct iovec *iov,
5337 	                              int iovcnt, uint64_t off, rbd_completion_t c)
5338 	{
5339 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5340 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5341 	
5342 	  // convert the scatter list into a bufferlist
5343 	  auto aio_completion = get_aio_completion(comp);
5344 	  ssize_t len = 0;
5345 	  bufferlist bl;
5346 	  for (int i = 0; i < iovcnt; ++i) {
5347 	    const struct iovec &io = iov[i];
5348 	    len += io.iov_len;
5349 	    if (len < 0) {
5350 	      break;
5351 	    }
5352 	
5353 	    bl.push_back(create_write_raw(ictx, static_cast<char*>(io.iov_base),
5354 	                                  io.iov_len, aio_completion));
5355 	  }
5356 	
5357 	  int r = 0;
5358 	  if (iovcnt <= 0 || len < 0) {
5359 	    r = -EINVAL;
5360 	  }
5361 	
5362 	  tracepoint(librbd, aio_write_enter, ictx, ictx->name.c_str(),
5363 	             ictx->snap_name.c_str(), ictx->read_only, off, len, NULL,
5364 	             comp->pc);
5365 	  if (r == 0) {
5366 	    ictx->io_work_queue->aio_write(aio_completion, off, len, std::move(bl), 0);
5367 	  }
5368 	  tracepoint(librbd, aio_write_exit, r);
5369 	  return r;
5370 	}
5371 	
5372 	extern "C" int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len,
5373 				       rbd_completion_t c)
5374 	{
5375 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5376 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5377 	  tracepoint(librbd, aio_discard_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, comp->pc);
5378 	  ictx->io_work_queue->aio_discard(
5379 	    get_aio_completion(comp), off, len, ictx->discard_granularity_bytes);
5380 	  tracepoint(librbd, aio_discard_exit, 0);
5381 	  return 0;
5382 	}
5383 	
5384 	extern "C" int rbd_aio_read(rbd_image_t image, uint64_t off, size_t len,
5385 				    char *buf, rbd_completion_t c)
5386 	{
5387 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5388 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5389 	  tracepoint(librbd, aio_read_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, buf, comp->pc);
5390 	  ictx->io_work_queue->aio_read(get_aio_completion(comp), off, len,
5391 	                                librbd::io::ReadResult{buf, len}, 0);
5392 	  tracepoint(librbd, aio_read_exit, 0);
5393 	  return 0;
5394 	}
5395 	
5396 	extern "C" int rbd_aio_read2(rbd_image_t image, uint64_t off, size_t len,
5397 				      char *buf, rbd_completion_t c, int op_flags)
5398 	{
5399 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5400 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5401 	  tracepoint(librbd, aio_read2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
5402 		      ictx->read_only, off, len, buf, comp->pc, op_flags);
5403 	  ictx->io_work_queue->aio_read(get_aio_completion(comp), off, len,
5404 	                                librbd::io::ReadResult{buf, len},op_flags);
5405 	  tracepoint(librbd, aio_read_exit, 0);
5406 	  return 0;
5407 	}
5408 	
5409 	extern "C" int rbd_aio_readv(rbd_image_t image, const struct iovec *iov,
5410 	                             int iovcnt, uint64_t off, rbd_completion_t c)
5411 	{
5412 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5413 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5414 	
5415 	  ssize_t len = 0;
5416 	  for (int i = 0; i < iovcnt; ++i) {
5417 	    len += iov[i].iov_len;
5418 	    if (len < 0) {
5419 	      break;
5420 	    }
5421 	  }
5422 	
5423 	  int r = 0;
5424 	  if (iovcnt == 0 || len < 0) {
5425 	    r = -EINVAL;
5426 	  }
5427 	
5428 	  tracepoint(librbd, aio_read_enter, ictx, ictx->name.c_str(),
5429 	             ictx->snap_name.c_str(), ictx->read_only, off, len, NULL,
5430 	             comp->pc);
5431 	  if (r == 0) {
5432 	    librbd::io::ReadResult read_result;
5433 	    if (iovcnt == 1) {
5434 	      read_result = librbd::io::ReadResult(
5435 	        static_cast<char *>(iov[0].iov_base), iov[0].iov_len);
5436 	    } else {
5437 	      read_result = librbd::io::ReadResult(iov, iovcnt);
5438 	    }
5439 	    ictx->io_work_queue->aio_read(get_aio_completion(comp), off, len,
5440 	                                  std::move(read_result), 0);
5441 	  }
5442 	  tracepoint(librbd, aio_read_exit, r);
5443 	  return r;
5444 	}
5445 	
5446 	extern "C" int rbd_flush(rbd_image_t image)
5447 	{
5448 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5449 	  tracepoint(librbd, flush_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
5450 	  int r = ictx->io_work_queue->flush();
5451 	  tracepoint(librbd, flush_exit, r);
5452 	  return r;
5453 	}
5454 	
5455 	extern "C" int rbd_aio_flush(rbd_image_t image, rbd_completion_t c)
5456 	{
5457 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5458 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5459 	  tracepoint(librbd, aio_flush_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, comp->pc);
5460 	  ictx->io_work_queue->aio_flush(get_aio_completion(comp));
5461 	  tracepoint(librbd, aio_flush_exit, 0);
5462 	  return 0;
5463 	}
5464 	
5465 	extern "C" int rbd_aio_writesame(rbd_image_t image, uint64_t off, size_t len,
5466 	                                 const char *buf, size_t data_len, rbd_completion_t c,
5467 	                                 int op_flags)
5468 	{
5469 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5470 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5471 	  tracepoint(librbd, aio_writesame_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
5472 	             ictx->read_only, off, len, data_len == 0 ? NULL : buf, data_len, comp->pc,
5473 	             op_flags);
5474 	
5475 	  if (data_len == 0 || len % data_len) {
5476 	    tracepoint(librbd, aio_writesame_exit, -EINVAL);
5477 	    return -EINVAL;
5478 	  }
5479 	
5480 	  bool discard_zero = ictx->config.get_val<bool>("rbd_discard_on_zeroed_write_same");
5481 	  if (discard_zero && mem_is_zero(buf, data_len)) {
5482 	    ictx->io_work_queue->aio_discard(get_aio_completion(comp), off, len, 0);
5483 	    tracepoint(librbd, aio_writesame_exit, 0);
5484 	    return 0;
5485 	  }
5486 	
5487 	  auto aio_completion = get_aio_completion(comp);
5488 	  bufferlist bl;
5489 	  bl.push_back(create_write_raw(ictx, buf, data_len, aio_completion));
5490 	  ictx->io_work_queue->aio_writesame(aio_completion, off, len, std::move(bl),
5491 	                                     op_flags);
5492 	  tracepoint(librbd, aio_writesame_exit, 0);
5493 	  return 0;
5494 	}
5495 	
5496 	extern "C" ssize_t rbd_aio_compare_and_write(rbd_image_t image, uint64_t off,
5497 	                                             size_t len, const char *cmp_buf,
5498 	                                             const char *buf, rbd_completion_t c,
5499 	                                             uint64_t *mismatch_off,
5500 	                                             int op_flags)
5501 	{
5502 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5503 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5504 	  tracepoint(librbd, aio_compare_and_write_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
5505 		      ictx->read_only, off, len, cmp_buf, buf, comp->pc, op_flags);
5506 	
5507 	  auto aio_completion = get_aio_completion(comp);
5508 	  bufferlist cmp_bl;
5509 	  cmp_bl.push_back(create_write_raw(ictx, cmp_buf, len, aio_completion));
5510 	  bufferlist bl;
5511 	  bl.push_back(create_write_raw(ictx, buf, len, aio_completion));
5512 	  ictx->io_work_queue->aio_compare_and_write(aio_completion, off, len,
5513 	                                             std::move(cmp_bl), std::move(bl),
5514 	                                             mismatch_off, op_flags, false);
5515 	
5516 	  tracepoint(librbd, aio_compare_and_write_exit, 0);
5517 	  return 0;
5518 	}
5519 	
5520 	extern "C" int rbd_invalidate_cache(rbd_image_t image)
5521 	{
5522 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5523 	  tracepoint(librbd, invalidate_cache_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
5524 	  int r = librbd::invalidate_cache(ictx);
5525 	  tracepoint(librbd, invalidate_cache_exit, r);
5526 	  return r;
5527 	}
5528 	
5529 	extern "C" int rbd_poll_io_events(rbd_image_t image, rbd_completion_t *comps, int numcomp)
5530 	{
5531 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5532 	  librbd::io::AioCompletion *cs[numcomp];
5533 	  tracepoint(librbd, poll_io_events_enter, ictx, numcomp);
5534 	  int r = librbd::poll_io_events(ictx, cs, numcomp);
5535 	  tracepoint(librbd, poll_io_events_exit, r);
5536 	  if (r > 0) {
5537 	    for (int i = 0; i < r; ++i)
5538 	      comps[i] = cs[i]->rbd_comp;
5539 	  }
5540 	  return r;
5541 	}
5542 	
5543 	extern "C" int rbd_metadata_get(rbd_image_t image, const char *key, char *value, size_t *vallen)
5544 	{
5545 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5546 	  string val_s;
5547 	  tracepoint(librbd, metadata_get_enter, ictx, key);
5548 	  int r = librbd::metadata_get(ictx, key, &val_s);
5549 	  if (r < 0) {
5550 	    tracepoint(librbd, metadata_get_exit, r, key, NULL);
5551 	    return r;
5552 	  }
5553 	  if (*vallen < val_s.size() + 1) {
5554 	    r = -ERANGE;
5555 	    *vallen = val_s.size() + 1;
5556 	    tracepoint(librbd, metadata_get_exit, r, key, NULL);
5557 	  } else {
5558 	    strncpy(value, val_s.c_str(), val_s.size() + 1);
5559 	    tracepoint(librbd, metadata_get_exit, r, key, value);
5560 	  }
5561 	  return r;
5562 	}
5563 	
5564 	extern "C" int rbd_metadata_set(rbd_image_t image, const char *key, const char *value)
5565 	{
5566 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5567 	  tracepoint(librbd, metadata_set_enter, ictx, key, value);
5568 	  int r = ictx->operations->metadata_set(key, value);
5569 	  tracepoint(librbd, metadata_set_exit, r);
5570 	  return r;
5571 	}
5572 	
5573 	extern "C" int rbd_metadata_remove(rbd_image_t image, const char *key)
5574 	{
5575 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5576 	  tracepoint(librbd, metadata_remove_enter, ictx, key);
5577 	  int r = ictx->operations->metadata_remove(key);
5578 	  tracepoint(librbd, metadata_remove_exit, r);
5579 	  return r;
5580 	}
5581 	
5582 	extern "C" int rbd_metadata_list(rbd_image_t image, const char *start, uint64_t max,
5583 	                                 char *key, size_t *key_len, char *value, size_t *val_len)
5584 	{
5585 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5586 	  tracepoint(librbd, metadata_list_enter, ictx);
5587 	  map<string, bufferlist> pairs;
5588 	  int r = librbd::metadata_list(ictx, start, max, &pairs);
5589 	  size_t key_total_len = 0, val_total_len = 0;
5590 	  bool too_short = false;
5591 	  for (map<string, bufferlist>::iterator it = pairs.begin();
5592 	       it != pairs.end(); ++it) {
5593 	    key_total_len += it->first.size() + 1;
5594 	    val_total_len += it->second.length() + 1;
5595 	  }
5596 	  if (*key_len < key_total_len || *val_len < val_total_len)
5597 	    too_short = true;
5598 	  *key_len = key_total_len;
5599 	  *val_len = val_total_len;
5600 	  if (too_short) {
5601 	    tracepoint(librbd, metadata_list_exit, -ERANGE);
5602 	    return -ERANGE;
5603 	  }
5604 	
5605 	  char *key_p = key, *value_p = value;
5606 	
5607 	  for (map<string, bufferlist>::iterator it = pairs.begin();
5608 	       it != pairs.end(); ++it) {
5609 	    strncpy(key_p, it->first.c_str(), it->first.size() + 1);
5610 	    key_p += it->first.size() + 1;
5611 	    strncpy(value_p, it->second.c_str(), it->second.length());
5612 	    value_p += it->second.length();
5613 	    *value_p = '\0';
5614 	    value_p++;
5615 	    tracepoint(librbd, metadata_list_entry, it->first.c_str(), it->second.c_str());
5616 	  }
5617 	  tracepoint(librbd, metadata_list_exit, r);
5618 	  return r;
5619 	}
5620 	
5621 	extern "C" int rbd_mirror_image_enable(rbd_image_t image)
5622 	{
5623 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5624 	  return librbd::api::Mirror<>::image_enable(ictx, false);
5625 	}
5626 	
5627 	extern "C" int rbd_mirror_image_disable(rbd_image_t image, bool force)
5628 	{
5629 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5630 	  return librbd::api::Mirror<>::image_disable(ictx, force);
5631 	}
5632 	
5633 	extern "C" int rbd_mirror_image_promote(rbd_image_t image, bool force)
5634 	{
5635 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5636 	  return librbd::api::Mirror<>::image_promote(ictx, force);
5637 	}
5638 	
5639 	extern "C" int rbd_mirror_image_demote(rbd_image_t image)
5640 	{
5641 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5642 	  return librbd::api::Mirror<>::image_demote(ictx);
5643 	}
5644 	
5645 	extern "C" int rbd_mirror_image_resync(rbd_image_t image)
5646 	{
5647 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5648 	  return librbd::api::Mirror<>::image_resync(ictx);
5649 	}
5650 	
5651 	extern "C" int rbd_mirror_image_get_info(rbd_image_t image,
5652 	                                         rbd_mirror_image_info_t *mirror_image_info,
5653 	                                         size_t info_size)
5654 	{
5655 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5656 	
5657 	  if (sizeof(rbd_mirror_image_info_t) != info_size) {
5658 	    return -ERANGE;
5659 	  }
5660 	
5661 	  librbd::mirror_image_info_t cpp_mirror_image;
5662 	  int r = librbd::api::Mirror<>::image_get_info(ictx, &cpp_mirror_image);
5663 	  if (r < 0) {
5664 	    return r;
5665 	  }
5666 	
5667 	  mirror_image_info_cpp_to_c(cpp_mirror_image, mirror_image_info);
5668 	  return 0;
5669 	}
5670 	
5671 	extern "C" int rbd_mirror_image_get_status(rbd_image_t image,
5672 						   rbd_mirror_image_status_t *status,
5673 						   size_t status_size)
5674 	{
5675 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5676 	
5677 	  if (sizeof(rbd_mirror_image_status_t) != status_size) {
5678 	    return -ERANGE;
5679 	  }
5680 	
5681 	  librbd::mirror_image_status_t cpp_status;
5682 	  int r = librbd::api::Mirror<>::image_get_status(ictx, &cpp_status);
5683 	  if (r < 0) {
5684 	    return r;
5685 	  }
5686 	
5687 	  mirror_image_status_cpp_to_c(cpp_status, status);
5688 	  return 0;
5689 	}
5690 	
5691 	extern "C" int rbd_mirror_image_get_instance_id(rbd_image_t image,
5692 	                                                char *instance_id,
5693 	                                                size_t *instance_id_max_length)
5694 	{
5695 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5696 	
5697 	  std::string cpp_instance_id;
5698 	  int r = librbd::api::Mirror<>::image_get_instance_id(ictx, &cpp_instance_id);
5699 	  if (r < 0) {
5700 	    return r;
5701 	  }
5702 	
5703 	  if (cpp_instance_id.size() >= *instance_id_max_length) {
5704 	    *instance_id_max_length = cpp_instance_id.size() + 1;
5705 	    return -ERANGE;
5706 	  }
5707 	
5708 	  strcpy(instance_id, cpp_instance_id.c_str());
5709 	  *instance_id_max_length = cpp_instance_id.size() + 1;
5710 	  return 0;
5711 	}
5712 	
5713 	extern "C" int rbd_aio_mirror_image_promote(rbd_image_t image, bool force,
5714 	                                            rbd_completion_t c) {
5715 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5716 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5717 	  librbd::api::Mirror<>::image_promote(
5718 	    ictx, force, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
5719 	                                     get_aio_completion(comp)));
5720 	  return 0;
5721 	}
5722 	
5723 	extern "C" int rbd_aio_mirror_image_demote(rbd_image_t image,
5724 	                                           rbd_completion_t c) {
5725 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5726 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5727 	  librbd::api::Mirror<>::image_demote(
5728 	    ictx, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
5729 	                              get_aio_completion(comp)));
5730 	  return 0;
5731 	}
5732 	
5733 	extern "C" int rbd_aio_mirror_image_get_info(rbd_image_t image,
5734 	                                             rbd_mirror_image_info_t *info,
5735 	                                             size_t info_size,
5736 	                                             rbd_completion_t c) {
5737 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5738 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5739 	
5740 	  if (sizeof(rbd_mirror_image_info_t) != info_size) {
5741 	    return -ERANGE;
5742 	  }
5743 	
5744 	  auto ctx = new C_MirrorImageGetInfo(
5745 	    info, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
5746 	                              get_aio_completion(comp)));
5747 	  librbd::api::Mirror<>::image_get_info(
5748 	    ictx, &ctx->cpp_mirror_image_info, ctx);
5749 	  return 0;
5750 	}
5751 	
5752 	extern "C" int rbd_aio_mirror_image_get_status(rbd_image_t image,
5753 	                                               rbd_mirror_image_status_t *status,
5754 	                                               size_t status_size,
5755 	                                               rbd_completion_t c) {
5756 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5757 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5758 	
5759 	  if (sizeof(rbd_mirror_image_status_t) != status_size) {
5760 	    return -ERANGE;
5761 	  }
5762 	
5763 	  auto ctx = new C_MirrorImageGetStatus(
5764 	    status, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
5765 	                                get_aio_completion(comp)));
5766 	  librbd::api::Mirror<>::image_get_status(ictx, &ctx->cpp_mirror_image_status,
5767 	                                          ctx);
5768 	  return 0;
5769 	}
5770 	
5771 	extern "C" int rbd_update_watch(rbd_image_t image, uint64_t *handle,
5772 					rbd_update_callback_t watch_cb, void *arg)
5773 	{
5774 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5775 	  C_UpdateWatchCB *wctx = new C_UpdateWatchCB(watch_cb, arg);
5776 	  tracepoint(librbd, update_watch_enter, ictx, wctx);
5777 	  int r = ictx->state->register_update_watcher(wctx, &wctx->handle);
5778 	  tracepoint(librbd, update_watch_exit, r, wctx->handle);
5779 	  *handle = reinterpret_cast<uint64_t>(wctx);
5780 	  return r;
5781 	}
5782 	
5783 	extern "C" int rbd_update_unwatch(rbd_image_t image, uint64_t handle)
5784 	{
5785 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
5786 	  C_UpdateWatchCB *wctx = reinterpret_cast<C_UpdateWatchCB *>(handle);
5787 	  tracepoint(librbd, update_unwatch_enter, ictx, wctx->handle);
5788 	  int r = ictx->state->unregister_update_watcher(wctx->handle);
5789 	  delete wctx;
5790 	  tracepoint(librbd, update_unwatch_exit, r);
5791 	  return r;
5792 	}
5793 	
5794 	extern "C" int rbd_aio_is_complete(rbd_completion_t c)
5795 	{
5796 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5797 	  return comp->is_complete();
5798 	}
5799 	
5800 	extern "C" int rbd_aio_wait_for_complete(rbd_completion_t c)
5801 	{
5802 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5803 	  return comp->wait_for_complete();
5804 	}
5805 	
5806 	extern "C" ssize_t rbd_aio_get_return_value(rbd_completion_t c)
5807 	{
5808 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5809 	  return comp->get_return_value();
5810 	}
5811 	
5812 	extern "C" void *rbd_aio_get_arg(rbd_completion_t c)
5813 	{
5814 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5815 	  return comp->get_arg();
5816 	}
5817 	
5818 	extern "C" void rbd_aio_release(rbd_completion_t c)
5819 	{
5820 	  librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
5821 	  comp->release();
5822 	}
5823 	
5824 	extern "C" int rbd_group_create(rados_ioctx_t p, const char *name)
5825 	{
5826 	  librados::IoCtx io_ctx;
5827 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
5828 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
5829 	  tracepoint(librbd, group_create_enter, io_ctx.get_pool_name().c_str(),
5830 	             io_ctx.get_id(), name);
5831 	  int r = librbd::api::Group<>::create(io_ctx, name);
5832 	  tracepoint(librbd, group_create_exit, r);
5833 	  return r;
5834 	}
5835 	
5836 	extern "C" int rbd_group_remove(rados_ioctx_t p, const char *name)
5837 	{
5838 	  librados::IoCtx io_ctx;
5839 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
5840 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
5841 	  tracepoint(librbd, group_remove_enter, io_ctx.get_pool_name().c_str(),
5842 	             io_ctx.get_id(), name);
5843 	  int r = librbd::api::Group<>::remove(io_ctx, name);
5844 	  tracepoint(librbd, group_remove_exit, r);
5845 	  return r;
5846 	}
5847 	
5848 	extern "C" int rbd_group_list(rados_ioctx_t p, char *names, size_t *size)
5849 	{
5850 	  librados::IoCtx io_ctx;
5851 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
5852 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
5853 	  tracepoint(librbd, group_list_enter, io_ctx.get_pool_name().c_str(),
5854 	             io_ctx.get_id());
5855 	
5856 	  vector<string> cpp_names;
5857 	  int r = librbd::api::Group<>::list(io_ctx, &cpp_names);
5858 	
5859 	  if (r < 0) {
5860 	    tracepoint(librbd, group_list_exit, r);
5861 	    return r;
5862 	  }
5863 	
5864 	  size_t expected_size = 0;
5865 	
5866 	  for (size_t i = 0; i < cpp_names.size(); i++) {
5867 	    expected_size += cpp_names[i].size() + 1;
5868 	  }
5869 	  if (*size < expected_size) {
5870 	    *size = expected_size;
5871 	    tracepoint(librbd, group_list_exit, -ERANGE);
5872 	    return -ERANGE;
5873 	  }
5874 	
5875 	  if (names == NULL) {
5876 	    tracepoint(librbd, group_list_exit, -EINVAL);
5877 	    return -EINVAL;
5878 	  }
5879 	
5880 	  for (int i = 0; i < (int)cpp_names.size(); i++) {
5881 	    const char* name = cpp_names[i].c_str();
5882 	    tracepoint(librbd, group_list_entry, name);
5883 	    strcpy(names, name);
5884 	    names += strlen(names) + 1;
5885 	  }
5886 	  tracepoint(librbd, group_list_exit, (int)expected_size);
5887 	  return (int)expected_size;
5888 	}
5889 	
5890 	extern "C" int rbd_group_rename(rados_ioctx_t p, const char *src_name,
5891 	                                const char *dest_name)
5892 	{
5893 	  librados::IoCtx io_ctx;
5894 	  librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
5895 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
5896 	  tracepoint(librbd, group_rename_enter, io_ctx.get_pool_name().c_str(),
5897 	             io_ctx.get_id(), src_name, dest_name);
5898 	  int r = librbd::api::Group<>::rename(io_ctx, src_name, dest_name);
5899 	  tracepoint(librbd, group_rename_exit, r);
5900 	  return r;
5901 	}
5902 	
5903 	extern "C" int rbd_group_image_add(rados_ioctx_t group_p,
5904 	                                   const char *group_name,
5905 	                                   rados_ioctx_t image_p,
5906 	                                   const char *image_name)
5907 	{
5908 	  librados::IoCtx group_ioctx;
5909 	  librados::IoCtx image_ioctx;
5910 	
5911 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
5912 	  librados::IoCtx::from_rados_ioctx_t(image_p, image_ioctx);
5913 	
5914 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
5915 	  tracepoint(librbd, group_image_add_enter, group_ioctx.get_pool_name().c_str(),
5916 		     group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(),
5917 		     image_ioctx.get_id(), image_name);
5918 	
5919 	  int r = librbd::api::Group<>::image_add(group_ioctx, group_name, image_ioctx,
5920 	                                          image_name);
5921 	
5922 	  tracepoint(librbd, group_image_add_exit, r);
5923 	  return r;
5924 	}
5925 	
5926 	extern "C" int rbd_group_image_remove(rados_ioctx_t group_p,
5927 	                                      const char *group_name,
5928 	                                      rados_ioctx_t image_p,
5929 	                                      const char *image_name)
5930 	{
5931 	  librados::IoCtx group_ioctx;
5932 	  librados::IoCtx image_ioctx;
5933 	
5934 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
5935 	  librados::IoCtx::from_rados_ioctx_t(image_p, image_ioctx);
5936 	
5937 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
5938 	  tracepoint(librbd, group_image_remove_enter, group_ioctx.get_pool_name().c_str(),
5939 		     group_ioctx.get_id(), group_name, image_ioctx.get_pool_name().c_str(),
5940 		     image_ioctx.get_id(), image_name);
5941 	
5942 	  int r = librbd::api::Group<>::image_remove(group_ioctx, group_name,
5943 	                                             image_ioctx, image_name);
5944 	
5945 	  tracepoint(librbd, group_image_remove_exit, r);
5946 	  return r;
5947 	}
5948 	
5949 	extern "C" int rbd_group_image_remove_by_id(rados_ioctx_t group_p,
5950 	                                            const char *group_name,
5951 	                                            rados_ioctx_t image_p,
5952 	                                            const char *image_id)
5953 	{
5954 	  librados::IoCtx group_ioctx;
5955 	  librados::IoCtx image_ioctx;
5956 	
5957 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
5958 	  librados::IoCtx::from_rados_ioctx_t(image_p, image_ioctx);
5959 	
5960 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
5961 	  tracepoint(librbd, group_image_remove_by_id_enter,
5962 	             group_ioctx.get_pool_name().c_str(),
5963 	             group_ioctx.get_id(), group_name,
5964 	             image_ioctx.get_pool_name().c_str(),
5965 	             image_ioctx.get_id(), image_id);
5966 	
5967 	  int r = librbd::api::Group<>::image_remove_by_id(group_ioctx, group_name,
5968 	                                                   image_ioctx, image_id);
5969 	
5970 	  tracepoint(librbd, group_image_remove_by_id_exit, r);
5971 	  return r;
5972 	}
5973 	
5974 	extern "C" int rbd_group_image_list(rados_ioctx_t group_p,
5975 					    const char *group_name,
5976 					    rbd_group_image_info_t *images,
5977 	                                    size_t group_image_info_size,
5978 					    size_t *image_size)
5979 	{
5980 	  librados::IoCtx group_ioctx;
5981 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
5982 	
5983 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
5984 	  tracepoint(librbd, group_image_list_enter,
5985 	             group_ioctx.get_pool_name().c_str(),
5986 		     group_ioctx.get_id(), group_name);
5987 	  memset(images, 0, sizeof(*images) * *image_size);
5988 	
5989 	  if (group_image_info_size != sizeof(rbd_group_image_info_t)) {
5990 	    *image_size = 0;
5991 	    tracepoint(librbd, group_image_list_exit, -ERANGE);
5992 	    return -ERANGE;
5993 	  }
5994 	
5995 	  std::vector<librbd::group_image_info_t> cpp_images;
5996 	  int r = librbd::api::Group<>::image_list(group_ioctx, group_name,
5997 	                                           &cpp_images);
5998 	
5999 	  if (r == -ENOENT) {
6000 	    tracepoint(librbd, group_image_list_exit, 0);
6001 	    *image_size = 0;
6002 	    return 0;
6003 	  }
6004 	
6005 	  if (r < 0) {
6006 	    tracepoint(librbd, group_image_list_exit, r);
6007 	    return r;
6008 	  }
6009 	
6010 	  if (*image_size < cpp_images.size()) {
6011 	    *image_size = cpp_images.size();
6012 	    tracepoint(librbd, group_image_list_exit, -ERANGE);
6013 	    return -ERANGE;
6014 	  }
6015 	
6016 	  for (size_t i = 0; i < cpp_images.size(); ++i) {
6017 	    group_image_status_cpp_to_c(cpp_images[i], &images[i]);
6018 	  }
6019 	
6020 	  r = *image_size = cpp_images.size();
6021 	  tracepoint(librbd, group_image_list_exit, r);
6022 	  return r;
6023 	}
6024 	
6025 	extern "C" int rbd_group_info_cleanup(rbd_group_info_t *group_info,
6026 	                                      size_t group_info_size) {
6027 	  if (group_info_size != sizeof(rbd_group_info_t)) {
6028 	    return -ERANGE;
6029 	  }
6030 	
6031 	  free(group_info->name);
6032 	  return 0;
6033 	}
6034 	
6035 	extern "C" int rbd_group_image_list_cleanup(rbd_group_image_info_t *images,
6036 	                                            size_t group_image_info_size,
6037 	                                            size_t len) {
6038 	  if (group_image_info_size != sizeof(rbd_group_image_info_t)) {
6039 	    return -ERANGE;
6040 	  }
6041 	
6042 	  for (size_t i = 0; i < len; ++i) {
6043 	    free(images[i].name);
6044 	  }
6045 	  return 0;
6046 	}
6047 	
6048 	extern "C" int rbd_group_snap_create(rados_ioctx_t group_p,
6049 	                                     const char *group_name,
6050 	                                     const char *snap_name)
6051 	{
6052 	  librados::IoCtx group_ioctx;
6053 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
6054 	
6055 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
6056 	  tracepoint(librbd, group_snap_create_enter,
6057 	             group_ioctx.get_pool_name().c_str(),
6058 		     group_ioctx.get_id(), group_name, snap_name);
6059 	
6060 	  int r = librbd::api::Group<>::snap_create(group_ioctx, group_name, snap_name);
6061 	
6062 	  tracepoint(librbd, group_snap_create_exit, r);
6063 	
6064 	  return r;
6065 	}
6066 	
6067 	extern "C" int rbd_group_snap_remove(rados_ioctx_t group_p,
6068 	                                     const char *group_name,
6069 	                                     const char *snap_name)
6070 	{
6071 	  librados::IoCtx group_ioctx;
6072 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
6073 	
6074 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
6075 	  tracepoint(librbd, group_snap_remove_enter,
6076 	             group_ioctx.get_pool_name().c_str(),
6077 		     group_ioctx.get_id(), group_name, snap_name);
6078 	
6079 	  int r = librbd::api::Group<>::snap_remove(group_ioctx, group_name, snap_name);
6080 	
6081 	  tracepoint(librbd, group_snap_remove_exit, r);
6082 	
6083 	  return r;
6084 	}
6085 	
6086 	extern "C" int rbd_group_snap_rename(rados_ioctx_t group_p,
6087 	                                     const char *group_name,
6088 	                                     const char *old_snap_name,
6089 	                                     const char *new_snap_name)
6090 	{
6091 	  librados::IoCtx group_ioctx;
6092 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
6093 	
6094 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
6095 	  tracepoint(librbd, group_snap_rename_enter,
6096 	             group_ioctx.get_pool_name().c_str(), group_ioctx.get_id(),
6097 	             group_name, old_snap_name, new_snap_name);
6098 	
6099 	  int r = librbd::api::Group<>::snap_rename(group_ioctx, group_name,
6100 	                                            old_snap_name, new_snap_name);
6101 	
6102 	  tracepoint(librbd, group_snap_list_exit, r);
6103 	  return r;
6104 	}
6105 	
6106 	extern "C" int rbd_group_snap_list(rados_ioctx_t group_p,
6107 	                                   const char *group_name,
6108 	                                   rbd_group_snap_info_t *snaps,
6109 	                                   size_t group_snap_info_size,
6110 	                                   size_t *snaps_size)
6111 	{
6112 	  librados::IoCtx group_ioctx;
6113 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
6114 	
6115 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
6116 	  tracepoint(librbd, group_snap_list_enter, group_ioctx.get_pool_name().c_str(),
6117 		     group_ioctx.get_id(), group_name);
6118 	  memset(snaps, 0, sizeof(*snaps) * *snaps_size);
6119 	
6120 	  if (group_snap_info_size != sizeof(rbd_group_snap_info_t)) {
6121 	    *snaps_size = 0;
6122 	    tracepoint(librbd, group_snap_list_exit, -ERANGE);
6123 	    return -ERANGE;
6124 	  }
6125 	
6126 	  std::vector<librbd::group_snap_info_t> cpp_snaps;
6127 	  int r = librbd::api::Group<>::snap_list(group_ioctx, group_name, &cpp_snaps);
6128 	
6129 	  if (r == -ENOENT) {
6130 	    *snaps_size = 0;
6131 	    tracepoint(librbd, group_snap_list_exit, 0);
6132 	    return 0;
6133 	  }
6134 	
6135 	  if (r < 0) {
6136 	    tracepoint(librbd, group_snap_list_exit, r);
6137 	    return r;
6138 	  }
6139 	
6140 	  if (*snaps_size < cpp_snaps.size()) {
6141 	    *snaps_size = cpp_snaps.size();
6142 	    tracepoint(librbd, group_snap_list_exit, -ERANGE);
6143 	    return -ERANGE;
6144 	  }
6145 	
6146 	  for (size_t i = 0; i < cpp_snaps.size(); ++i) {
6147 	    group_snap_info_cpp_to_c(cpp_snaps[i], &snaps[i]);
6148 	  }
6149 	
6150 	  r = *snaps_size = cpp_snaps.size();
6151 	  tracepoint(librbd, group_snap_list_exit, r);
6152 	  return r;
6153 	}
6154 	
6155 	extern "C" int rbd_group_snap_list_cleanup(rbd_group_snap_info_t *snaps,
6156 	                                           size_t group_snap_info_size,
6157 	                                           size_t len) {
6158 	  if (group_snap_info_size != sizeof(rbd_group_snap_info_t)) {
6159 	    return -ERANGE;
6160 	  }
6161 	
6162 	  for (size_t i = 0; i < len; ++i) {
6163 	    free(snaps[i].name);
6164 	  }
6165 	  return 0;
6166 	}
6167 	
6168 	extern "C" int rbd_group_snap_rollback(rados_ioctx_t group_p,
6169 	                                       const char *group_name,
6170 	                                       const char *snap_name)
6171 	{
6172 	  librados::IoCtx group_ioctx;
6173 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
6174 	
6175 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
6176 	  tracepoint(librbd, group_snap_rollback_enter,
6177 	             group_ioctx.get_pool_name().c_str(),
6178 	             group_ioctx.get_id(), group_name, snap_name);
6179 	
6180 	  librbd::NoOpProgressContext prog_ctx;
6181 	  int r = librbd::api::Group<>::snap_rollback(group_ioctx, group_name,
6182 	                                              snap_name, prog_ctx);
6183 	
6184 	  tracepoint(librbd, group_snap_rollback_exit, r);
6185 	
6186 	  return r;
6187 	}
6188 	
6189 	extern "C" int rbd_group_snap_rollback_with_progress(rados_ioctx_t group_p,
6190 	                                                     const char *group_name,
6191 	                                                     const char *snap_name,
6192 	                                                     librbd_progress_fn_t cb,
6193 	                                                     void *cbdata)
6194 	{
6195 	  librados::IoCtx group_ioctx;
6196 	  librados::IoCtx::from_rados_ioctx_t(group_p, group_ioctx);
6197 	
6198 	  TracepointProvider::initialize<tracepoint_traits>(get_cct(group_ioctx));
6199 	  tracepoint(librbd, group_snap_rollback_enter,
6200 	             group_ioctx.get_pool_name().c_str(),
6201 	             group_ioctx.get_id(), group_name, snap_name);
6202 	
6203 	  librbd::CProgressContext prog_ctx(cb, cbdata);
6204 	  int r = librbd::api::Group<>::snap_rollback(group_ioctx, group_name,
6205 	                                              snap_name, prog_ctx);
6206 	
6207 	  tracepoint(librbd, group_snap_rollback_exit, r);
6208 	
6209 	  return r;
6210 	}
6211 	
6212 	extern "C" int rbd_snap_get_namespace_type(rbd_image_t image,
6213 						   uint64_t snap_id,
6214 						   rbd_snap_namespace_type_t *namespace_type) {
6215 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
6216 	  tracepoint(librbd, snap_get_namespace_type_enter, ictx, ictx->name.c_str());
6217 	  int r = librbd::api::Snapshot<>::get_namespace_type(ictx, snap_id,
6218 	                                                      namespace_type);
6219 	  tracepoint(librbd, snap_get_namespace_type_exit, r);
6220 	  return r;
6221 	}
6222 	
6223 	extern "C" int rbd_snap_get_group_namespace(rbd_image_t image, uint64_t snap_id,
6224 	                                            rbd_snap_group_namespace_t *group_snap,
6225 	                                            size_t snap_group_namespace_size) {
6226 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
6227 	  tracepoint(librbd, snap_get_group_namespace_enter, ictx,
6228 	             ictx->name.c_str());
6229 	
6230 	  if (snap_group_namespace_size != sizeof(rbd_snap_group_namespace_t)) {
6231 	    tracepoint(librbd, snap_get_group_namespace_exit, -ERANGE);
6232 	    return -ERANGE;
6233 	  }
6234 	
6235 	  librbd::snap_group_namespace_t group_namespace;
6236 	  int r = librbd::api::Snapshot<>::get_group_namespace(ictx, snap_id,
6237 	                                                       &group_namespace);
6238 	  if (r >= 0) {
6239 	    group_snap->group_pool = group_namespace.group_pool;
6240 	    group_snap->group_name = strdup(group_namespace.group_name.c_str());
6241 	    group_snap->group_snap_name =
6242 	      strdup(group_namespace.group_snap_name.c_str());
6243 	  }
6244 	
6245 	  tracepoint(librbd, snap_get_group_namespace_exit, r);
6246 	  return r;
6247 	}
6248 	
6249 	extern "C" int rbd_snap_group_namespace_cleanup(rbd_snap_group_namespace_t *group_snap,
6250 	                                                size_t snap_group_namespace_size) {
6251 	  if (snap_group_namespace_size != sizeof(rbd_snap_group_namespace_t)) {
6252 	    tracepoint(librbd, snap_get_group_namespace_exit, -ERANGE);
6253 	    return -ERANGE;
6254 	  }
6255 	
6256 	  free(group_snap->group_name);
6257 	  free(group_snap->group_snap_name);
6258 	  return 0;
6259 	}
6260 	
6261 	extern "C" int rbd_snap_get_trash_namespace(rbd_image_t image, uint64_t snap_id,
6262 	                                            char *original_name,
6263 	                                            size_t max_length) {
6264 	  librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
6265 	
6266 	  std::string cpp_original_name;
6267 	  int r = librbd::api::Snapshot<>::get_trash_namespace(ictx, snap_id,
6268 	                                                       &cpp_original_name);
6269 	  if (r < 0) {
6270 	    return r;
6271 	  }
6272 	
6273 	  if (cpp_original_name.length() >= max_length) {
6274 	    return -ERANGE;
6275 	  }
6276 	
6277 	  strcpy(original_name, cpp_original_name.c_str());
6278 	  return 0;
6279 	}
6280 	extern "C" int rbd_watchers_list(rbd_image_t image,
6281 					 rbd_image_watcher_t *watchers,
6282 					 size_t *max_watchers) {
6283 	  std::list<librbd::image_watcher_t> watcher_list;
6284 	  librbd::ImageCtx *ictx = (librbd::ImageCtx*)image;
6285 	
6286 	  tracepoint(librbd, list_watchers_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
6287 	  memset(watchers, 0, sizeof(*watchers) * *max_watchers);
6288 	  int r = librbd::list_watchers(ictx, watcher_list);
6289 	  if (r < 0) {
6290 	    tracepoint(librbd, list_watchers_exit, r, 0);
6291 	    return r;
6292 	  }
6293 	
6294 	  if (watcher_list.size() > *max_watchers) {
6295 	    *max_watchers = watcher_list.size();
6296 	    tracepoint(librbd, list_watchers_exit, -ERANGE, watcher_list.size());
6297 	    return -ERANGE;
6298 	  }
6299 	
6300 	  *max_watchers = 0;
6301 	  for (auto &watcher : watcher_list) {
6302 	    tracepoint(librbd, list_watchers_entry, watcher.addr.c_str(), watcher.id, watcher.cookie);
6303 	    watchers[*max_watchers].addr = strdup(watcher.addr.c_str());
6304 	    watchers[*max_watchers].id = watcher.id;
6305 	    watchers[*max_watchers].cookie = watcher.cookie;
6306 	    *max_watchers += 1;
6307 	  }
6308 	
6309 	  tracepoint(librbd, list_watchers_exit, r, watcher_list.size());
6310 	  return 0;
6311 	}
6312 	
6313 	extern "C" void rbd_watchers_list_cleanup(rbd_image_watcher_t *watchers,
6314 						  size_t num_watchers) {
6315 	  for (size_t i = 0; i < num_watchers; ++i) {
6316 	    free(watchers[i].addr);
6317 	  }
6318 	}
6319 	
6320 	extern "C" int rbd_config_image_list(rbd_image_t image,
6321 	                                     rbd_config_option_t *options,
6322 	                                     int *max_options) {
6323 	  librbd::ImageCtx *ictx = (librbd::ImageCtx*)image;
6324 	
6325 	  std::vector<librbd::config_option_t> option_vector;
6326 	  int r = librbd::api::Config<>::list(ictx, &option_vector);
6327 	  if (r < 0) {
6328 	    return r;
6329 	  }
6330 	
6331 	  if (*max_options < static_cast<int>(option_vector.size())) {
6332 	    *max_options = static_cast<int>(option_vector.size());
6333 	    return -ERANGE;
6334 	  }
6335 	
6336 	  for (int i = 0; i < static_cast<int>(option_vector.size()); ++i) {
6337 	    config_option_cpp_to_c(option_vector[i], &options[i]);
6338 	  }
6339 	  *max_options = static_cast<int>(option_vector.size());
6340 	  return 0;
6341 	}
6342 	
6343 	extern "C" void rbd_config_image_list_cleanup(rbd_config_option_t *options,
6344 	                                              int max_options) {
6345 	  for (int i = 0; i < max_options; ++i) {
6346 	    config_option_cleanup(options[i]);
6347 	  }
6348 	}
6349