Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / librbd.cc
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 "cls/rbd/cls_rbd_types.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/DiffIterate.h"
31 #include "librbd/api/Mirror.h"
32 #include "librbd/io/AioCompletion.h"
33 #include "librbd/io/ImageRequestWQ.h"
34 #include "librbd/io/ReadResult.h"
35 #include <algorithm>
36 #include <string>
37 #include <vector>
38
39 #ifdef WITH_LTTNG
40 #define TRACEPOINT_DEFINE
41 #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE
42 #include "tracing/librbd.h"
43 #undef TRACEPOINT_PROBE_DYNAMIC_LINKAGE
44 #undef TRACEPOINT_DEFINE
45 #else
46 #define tracepoint(...)
47 #endif
48
49 #define dout_subsys ceph_subsys_rbd
50 #undef dout_prefix
51 #define dout_prefix *_dout << "librbd: "
52
53 using std::string;
54 using std::vector;
55
56 using ceph::bufferlist;
57 using librados::snap_t;
58 using librados::IoCtx;
59
60 namespace {
61
62 TracepointProvider::Traits tracepoint_traits("librbd_tp.so", "rbd_tracing");
63
64 buffer::raw* create_write_raw(librbd::ImageCtx *ictx, const char *buf,
65                               size_t len) {
66   // TODO: until librados can guarantee memory won't be referenced after
67   // it ACKs a request, always make a copy of the user-provided memory
68   return buffer::copy(buf, len);
69 }
70
71 CephContext* get_cct(IoCtx &io_ctx) {
72   return reinterpret_cast<CephContext*>(io_ctx.cct());
73 }
74
75 librbd::io::AioCompletion* get_aio_completion(librbd::RBD::AioCompletion *comp) {
76   return reinterpret_cast<librbd::io::AioCompletion *>(comp->pc);
77 }
78
79 struct C_AioCompletion : public Context {
80   CephContext *cct;
81   librbd::io::aio_type_t aio_type;
82   librbd::io::AioCompletion* aio_comp;
83
84   C_AioCompletion(librbd::ImageCtx *ictx, librbd::io::aio_type_t aio_type,
85                   librbd::io::AioCompletion* aio_comp)
86     : cct(ictx->cct), aio_type(aio_type), aio_comp(aio_comp) {
87     aio_comp->init_time(ictx, aio_type);
88     aio_comp->get();
89   }
90
91   void finish(int r) override {
92     ldout(cct, 20) << "C_AioComplete::finish: r=" << r << dendl;
93     if (r < 0) {
94       aio_comp->fail(r);
95     } else {
96       aio_comp->lock.Lock();
97       aio_comp->complete();
98       aio_comp->put_unlock();
99     }
100   }
101 };
102
103 struct C_OpenComplete : public C_AioCompletion {
104   librbd::ImageCtx *ictx;
105   void **ictxp;
106   C_OpenComplete(librbd::ImageCtx *ictx, librbd::io::AioCompletion* comp,
107                  void **ictxp)
108     : C_AioCompletion(ictx, librbd::io::AIO_TYPE_OPEN, comp),
109       ictx(ictx), ictxp(ictxp) {
110   }
111   void finish(int r) override {
112     ldout(ictx->cct, 20) << "C_OpenComplete::finish: r=" << r << dendl;
113     if (r < 0) {
114       *ictxp = nullptr;
115     } else {
116       *ictxp = ictx;
117     }
118
119     C_AioCompletion::finish(r);
120   }
121 };
122
123 struct C_OpenAfterCloseComplete : public Context {
124   librbd::ImageCtx *ictx;
125   librbd::io::AioCompletion* comp;
126   void **ictxp;
127   C_OpenAfterCloseComplete(librbd::ImageCtx *ictx,
128                            librbd::io::AioCompletion* comp,
129                            void **ictxp)
130     : ictx(ictx), comp(comp), ictxp(ictxp) {
131   }
132   void finish(int r) override {
133     ldout(ictx->cct, 20) << "C_OpenAfterCloseComplete::finish: r=" << r
134                          << dendl;
135     delete reinterpret_cast<librbd::ImageCtx*>(*ictxp);
136     *ictxp = nullptr;
137
138     ictx->state->open(false, new C_OpenComplete(ictx, comp, ictxp));
139   }
140 };
141
142 struct C_UpdateWatchCB : public librbd::UpdateWatchCtx {
143   rbd_update_callback_t watch_cb;
144   void *arg;
145   uint64_t handle = 0;
146
147   C_UpdateWatchCB(rbd_update_callback_t watch_cb, void *arg) :
148     watch_cb(watch_cb), arg(arg) {
149   }
150   void handle_notify() override {
151     watch_cb(arg);
152   }
153 };
154
155 void mirror_image_info_cpp_to_c(const librbd::mirror_image_info_t &cpp_info,
156                                 rbd_mirror_image_info_t *c_info) {
157   c_info->global_id = strdup(cpp_info.global_id.c_str());
158   c_info->state = cpp_info.state;
159   c_info->primary = cpp_info.primary;
160 }
161
162 void mirror_image_status_cpp_to_c(const librbd::mirror_image_status_t &cpp_status,
163                                   rbd_mirror_image_status_t *c_status) {
164   c_status->name = strdup(cpp_status.name.c_str());
165   mirror_image_info_cpp_to_c(cpp_status.info, &c_status->info);
166   c_status->state = cpp_status.state;
167   c_status->description = strdup(cpp_status.description.c_str());
168   c_status->last_update = cpp_status.last_update;
169   c_status->up = cpp_status.up;
170 }
171
172 void trash_image_info_cpp_to_c(const librbd::trash_image_info_t &cpp_info,
173                                rbd_trash_image_info_t *c_info) {
174   c_info->id = strdup(cpp_info.id.c_str());
175   c_info->name = strdup(cpp_info.name.c_str());
176   c_info->source = cpp_info.source;
177   c_info->deletion_time = cpp_info.deletion_time;
178   c_info->deferment_end_time = cpp_info.deferment_end_time;
179 }
180
181 struct C_MirrorImageGetInfo : public Context {
182     rbd_mirror_image_info_t *mirror_image_info;
183   Context *on_finish;
184
185   librbd::mirror_image_info_t cpp_mirror_image_info;
186
187   C_MirrorImageGetInfo(rbd_mirror_image_info_t *mirror_image_info,
188                          Context *on_finish)
189     : mirror_image_info(mirror_image_info), on_finish(on_finish) {
190   }
191
192   void finish(int r) override {
193     if (r < 0) {
194       on_finish->complete(r);
195       return;
196     }
197
198     mirror_image_info_cpp_to_c(cpp_mirror_image_info, mirror_image_info);
199     on_finish->complete(0);
200   }
201 };
202
203 struct C_MirrorImageGetStatus : public Context {
204   rbd_mirror_image_status_t *mirror_image_status;
205   Context *on_finish;
206
207   librbd::mirror_image_status_t cpp_mirror_image_status;
208
209   C_MirrorImageGetStatus(rbd_mirror_image_status_t *mirror_image_status,
210                          Context *on_finish)
211     : mirror_image_status(mirror_image_status), on_finish(on_finish) {
212   }
213
214   void finish(int r) override {
215     if (r < 0) {
216       on_finish->complete(r);
217       return;
218     }
219
220     mirror_image_status_cpp_to_c(cpp_mirror_image_status, mirror_image_status);
221     on_finish->complete(0);
222   }
223 };
224
225 } // anonymous namespace
226
227 namespace librbd {
228   ProgressContext::~ProgressContext()
229   {
230   }
231
232   class CProgressContext : public ProgressContext
233   {
234   public:
235     CProgressContext(librbd_progress_fn_t fn, void *data)
236       : m_fn(fn), m_data(data)
237     {
238     }
239     int update_progress(uint64_t offset, uint64_t src_size) override
240     {
241       return m_fn(offset, src_size, m_data);
242     }
243   private:
244     librbd_progress_fn_t m_fn;
245     void *m_data;
246   };
247
248   /*
249     RBD
250   */
251   RBD::RBD()
252   {
253   }
254
255   RBD::~RBD()
256   {
257   }
258
259   void RBD::version(int *major, int *minor, int *extra)
260   {
261     rbd_version(major, minor, extra);
262   }
263
264   int RBD::open(IoCtx& io_ctx, Image& image, const char *name)
265   {
266     return open(io_ctx, image, name, NULL);
267   }
268
269   int RBD::open_by_id(IoCtx& io_ctx, Image& image, const char *id)
270   {
271     return open_by_id(io_ctx, image, id, nullptr);
272   }
273
274   int RBD::open(IoCtx& io_ctx, Image& image, const char *name,
275                 const char *snap_name)
276   {
277     ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, false);
278     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
279     tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
280
281     if (image.ctx != NULL) {
282       reinterpret_cast<ImageCtx*>(image.ctx)->state->close();
283       image.ctx = NULL;
284     }
285
286     int r = ictx->state->open(false);
287     if (r < 0) {
288       tracepoint(librbd, open_image_exit, r);
289       return r;
290     }
291
292     image.ctx = (image_ctx_t) ictx;
293     tracepoint(librbd, open_image_exit, 0);
294     return 0;
295   }
296
297   int RBD::open_by_id(IoCtx& io_ctx, Image& image, const char *id,
298                       const char *snap_name)
299   {
300     ImageCtx *ictx = new ImageCtx("", id, snap_name, io_ctx, false);
301     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
302     tracepoint(librbd, open_image_by_id_enter, ictx, ictx->id.c_str(),
303                ictx->snap_name.c_str(), ictx->read_only);
304
305     if (image.ctx != nullptr) {
306       reinterpret_cast<ImageCtx*>(image.ctx)->state->close();
307       image.ctx = nullptr;
308     }
309
310     int r = ictx->state->open(false);
311     if (r < 0) {
312       tracepoint(librbd, open_image_by_id_exit, r);
313       return r;
314     }
315
316     image.ctx = (image_ctx_t) ictx;
317     tracepoint(librbd, open_image_by_id_exit, 0);
318     return 0;
319   }
320
321   int RBD::aio_open(IoCtx& io_ctx, Image& image, const char *name,
322                     const char *snap_name, RBD::AioCompletion *c)
323   {
324     ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, false);
325     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
326     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);
327
328     if (image.ctx != NULL) {
329       reinterpret_cast<ImageCtx*>(image.ctx)->state->close(
330         new C_OpenAfterCloseComplete(ictx, get_aio_completion(c), &image.ctx));
331     } else {
332       ictx->state->open(false, new C_OpenComplete(ictx, get_aio_completion(c),
333                                            &image.ctx));
334     }
335     tracepoint(librbd, aio_open_image_exit, 0);
336     return 0;
337   }
338
339   int RBD::aio_open_by_id(IoCtx& io_ctx, Image& image, const char *id,
340                           const char *snap_name, RBD::AioCompletion *c)
341   {
342     ImageCtx *ictx = new ImageCtx("", id, snap_name, io_ctx, false);
343     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
344     tracepoint(librbd, aio_open_image_by_id_enter, ictx, ictx->id.c_str(),
345                ictx->snap_name.c_str(), ictx->read_only, c->pc);
346
347     if (image.ctx != nullptr) {
348       reinterpret_cast<ImageCtx*>(image.ctx)->state->close(
349         new C_OpenAfterCloseComplete(ictx, get_aio_completion(c), &image.ctx));
350     } else {
351       ictx->state->open(false, new C_OpenComplete(ictx, get_aio_completion(c),
352                                                   &image.ctx));
353     }
354     tracepoint(librbd, aio_open_image_by_id_exit, 0);
355     return 0;
356   }
357
358   int RBD::open_read_only(IoCtx& io_ctx, Image& image, const char *name,
359                           const char *snap_name)
360   {
361     ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, true);
362     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
363     tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
364
365     if (image.ctx != NULL) {
366       reinterpret_cast<ImageCtx*>(image.ctx)->state->close();
367       image.ctx = NULL;
368     }
369
370     int r = ictx->state->open(false);
371     if (r < 0) {
372       tracepoint(librbd, open_image_exit, r);
373       return r;
374     }
375
376     image.ctx = (image_ctx_t) ictx;
377     tracepoint(librbd, open_image_exit, 0);
378     return 0;
379   }
380
381   int RBD::open_by_id_read_only(IoCtx& io_ctx, Image& image, const char *id,
382                                 const char *snap_name)
383   {
384     ImageCtx *ictx = new ImageCtx("", id, snap_name, io_ctx, true);
385     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
386     tracepoint(librbd, open_image_by_id_enter, ictx, ictx->id.c_str(),
387                ictx->snap_name.c_str(), ictx->read_only);
388
389     if (image.ctx != nullptr) {
390       reinterpret_cast<ImageCtx*>(image.ctx)->state->close();
391       image.ctx = nullptr;
392     }
393
394     int r = ictx->state->open(false);
395     if (r < 0) {
396       tracepoint(librbd, open_image_by_id_exit, r);
397       return r;
398     }
399
400     image.ctx = (image_ctx_t) ictx;
401     tracepoint(librbd, open_image_by_id_exit, 0);
402     return 0;
403   }
404
405   int RBD::aio_open_read_only(IoCtx& io_ctx, Image& image, const char *name,
406                               const char *snap_name, RBD::AioCompletion *c)
407   {
408     ImageCtx *ictx = new ImageCtx(name, "", snap_name, io_ctx, true);
409     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
410     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);
411
412     if (image.ctx != NULL) {
413       reinterpret_cast<ImageCtx*>(image.ctx)->state->close(
414         new C_OpenAfterCloseComplete(ictx, get_aio_completion(c), &image.ctx));
415     } else {
416       ictx->state->open(false, new C_OpenComplete(ictx, get_aio_completion(c),
417                                            &image.ctx));
418     }
419     tracepoint(librbd, aio_open_image_exit, 0);
420     return 0;
421   }
422
423   int RBD::aio_open_by_id_read_only(IoCtx& io_ctx, Image& image, const char *id,
424                                     const char *snap_name, RBD::AioCompletion *c)
425   {
426     ImageCtx *ictx = new ImageCtx("", id, snap_name, io_ctx, true);
427     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
428     tracepoint(librbd, aio_open_image_by_id_enter, ictx, ictx->id.c_str(),
429                ictx->snap_name.c_str(), ictx->read_only, c->pc);
430
431     if (image.ctx != nullptr) {
432       reinterpret_cast<ImageCtx*>(image.ctx)->state->close(
433         new C_OpenAfterCloseComplete(ictx, get_aio_completion(c), &image.ctx));
434     } else {
435       ictx->state->open(false, new C_OpenComplete(ictx, get_aio_completion(c),
436                                                   &image.ctx));
437     }
438     tracepoint(librbd, aio_open_image_by_id_exit, 0);
439     return 0;
440   }
441
442   int RBD::create(IoCtx& io_ctx, const char *name, uint64_t size, int *order)
443   {
444     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
445     tracepoint(librbd, create_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, *order);
446     int r = librbd::create(io_ctx, name, size, order);
447     tracepoint(librbd, create_exit, r, *order);
448     return r;
449   }
450
451   int RBD::create2(IoCtx& io_ctx, const char *name, uint64_t size,
452                    uint64_t features, int *order)
453   {
454     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
455     tracepoint(librbd, create2_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, features, *order);
456     int r = librbd::create(io_ctx, name, size, false, features, order, 0, 0);
457     tracepoint(librbd, create2_exit, r, *order);
458     return r;
459   }
460
461   int RBD::create3(IoCtx& io_ctx, const char *name, uint64_t size,
462                    uint64_t features, int *order, uint64_t stripe_unit,
463                    uint64_t stripe_count)
464   {
465     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
466     tracepoint(librbd, create3_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, features, *order, stripe_unit, stripe_count);
467     int r = librbd::create(io_ctx, name, size, false, features, order,
468                           stripe_unit, stripe_count);
469     tracepoint(librbd, create3_exit, r, *order);
470     return r;
471   }
472
473   int RBD::create4(IoCtx& io_ctx, const char *name, uint64_t size,
474                    ImageOptions& opts)
475   {
476     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
477     tracepoint(librbd, create4_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, opts.opts);
478     int r = librbd::create(io_ctx, name, "", size, opts, "", "", false);
479     tracepoint(librbd, create4_exit, r);
480     return r;
481   }
482
483   int RBD::clone(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
484                  IoCtx& c_ioctx, const char *c_name, uint64_t features,
485                  int *c_order)
486   {
487     TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioctx));
488     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);
489     int r = librbd::clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name,
490                          features, c_order, 0, 0);
491     tracepoint(librbd, clone_exit, r, *c_order);
492     return r;
493   }
494
495   int RBD::clone2(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
496                   IoCtx& c_ioctx, const char *c_name, uint64_t features,
497                   int *c_order, uint64_t stripe_unit, int stripe_count)
498   {
499     TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioctx));
500     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);
501     int r = librbd::clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name,
502                          features, c_order, stripe_unit, stripe_count);
503     tracepoint(librbd, clone2_exit, r, *c_order);
504     return r;
505   }
506
507   int RBD::clone3(IoCtx& p_ioctx, const char *p_name, const char *p_snap_name,
508                   IoCtx& c_ioctx, const char *c_name, ImageOptions& c_opts)
509   {
510     TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioctx));
511     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);
512     int r = librbd::clone(p_ioctx, p_name, p_snap_name, c_ioctx, c_name,
513                           c_opts);
514     tracepoint(librbd, clone3_exit, r);
515     return r;
516   }
517
518   int RBD::remove(IoCtx& io_ctx, const char *name)
519   {
520     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
521     tracepoint(librbd, remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name);
522     librbd::NoOpProgressContext prog_ctx;
523     int r = librbd::remove(io_ctx, name, "", prog_ctx);
524     tracepoint(librbd, remove_exit, r);
525     return r;
526   }
527
528   int RBD::remove_with_progress(IoCtx& io_ctx, const char *name,
529                                 ProgressContext& pctx)
530   {
531     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
532     tracepoint(librbd, remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name);
533     int r = librbd::remove(io_ctx, name, "", pctx);
534     tracepoint(librbd, remove_exit, r);
535     return r;
536   }
537
538   int RBD::trash_move(IoCtx &io_ctx, const char *name, uint64_t delay) {
539     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
540     tracepoint(librbd, trash_move_enter, io_ctx.get_pool_name().c_str(),
541                io_ctx.get_id(), name);
542     int r = librbd::trash_move(io_ctx, RBD_TRASH_IMAGE_SOURCE_USER, name,
543                                delay);
544     tracepoint(librbd, trash_move_exit, r);
545     return r;
546   }
547
548   int RBD::trash_get(IoCtx &io_ctx, const char *id, trash_image_info_t *info) {
549     return librbd::trash_get(io_ctx, id, info);
550   }
551
552   int RBD::trash_list(IoCtx &io_ctx, vector<trash_image_info_t> &entries) {
553     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
554     tracepoint(librbd, trash_list_enter,
555                io_ctx.get_pool_name().c_str(), io_ctx.get_id());
556     int r = librbd::trash_list(io_ctx, entries);
557 #ifdef WITH_LTTNG
558     if (r >= 0) {
559       for (const auto& entry : entries) {
560         tracepoint(librbd, trash_list_entry, entry.id.c_str());
561       }
562     }
563 #endif
564     tracepoint(librbd, trash_list_exit, r, r);
565     return r;
566   }
567
568   int RBD::trash_remove(IoCtx &io_ctx, const char *image_id, bool force) {
569     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
570     tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
571                io_ctx.get_id(), image_id, force);
572     librbd::NoOpProgressContext prog_ctx;
573     int r = librbd::trash_remove(io_ctx, image_id, force, prog_ctx);
574     tracepoint(librbd, trash_remove_exit, r);
575     return r;
576   }
577
578   int RBD::trash_remove_with_progress(IoCtx &io_ctx, const char *image_id,
579                                       bool force, ProgressContext &pctx) {
580     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
581     tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
582                io_ctx.get_id(), image_id, force);
583     int r = librbd::trash_remove(io_ctx, image_id, force, pctx);
584     tracepoint(librbd, trash_remove_exit, r);
585     return r;
586   }
587
588   int RBD::trash_restore(IoCtx &io_ctx, const char *id, const char *name) {
589     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
590     tracepoint(librbd, trash_undelete_enter, io_ctx.get_pool_name().c_str(),
591                io_ctx.get_id(), id, name);
592     int r = librbd::trash_restore(io_ctx, id, name);
593     tracepoint(librbd, trash_undelete_exit, r);
594     return r;
595   }
596
597   int RBD::list(IoCtx& io_ctx, vector<string>& names)
598   {
599     TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
600     tracepoint(librbd, list_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id());
601     int r = librbd::list(io_ctx, names);
602     if (r >= 0) {
603       for (vector<string>::iterator itr = names.begin(), end = names.end(); itr != end; ++itr) {
604         tracepoint(librbd, list_entry, itr->c_str());
605       }
606     }
607     tracepoint(librbd, list_exit, r, r);
608     return r;
609   }
610
611   int RBD::rename(IoCtx& src_io_ctx, const char *srcname, const char *destname)
612   {
613     TracepointProvider::initialize<tracepoint_traits>(get_cct(src_io_ctx));
614     tracepoint(librbd, rename_enter, src_io_ctx.get_pool_name().c_str(), src_io_ctx.get_id(), srcname, destname);
615     int r = librbd::rename(src_io_ctx, srcname, destname);
616     tracepoint(librbd, rename_exit, r);
617     return r;
618   }
619
620   int RBD::mirror_mode_get(IoCtx& io_ctx, rbd_mirror_mode_t *mirror_mode) {
621     return librbd::api::Mirror<>::mode_get(io_ctx, mirror_mode);
622   }
623
624   int RBD::mirror_mode_set(IoCtx& io_ctx, rbd_mirror_mode_t mirror_mode) {
625     return librbd::api::Mirror<>::mode_set(io_ctx, mirror_mode);
626   }
627
628   int RBD::mirror_peer_add(IoCtx& io_ctx, std::string *uuid,
629                            const std::string &cluster_name,
630                            const std::string &client_name) {
631     return librbd::api::Mirror<>::peer_add(io_ctx, uuid, cluster_name,
632                                            client_name);
633   }
634
635   int RBD::mirror_peer_remove(IoCtx& io_ctx, const std::string &uuid) {
636     return librbd::api::Mirror<>::peer_remove(io_ctx, uuid);
637   }
638
639   int RBD::mirror_peer_list(IoCtx& io_ctx, std::vector<mirror_peer_t> *peers) {
640     return librbd::api::Mirror<>::peer_list(io_ctx, peers);
641   }
642
643   int RBD::mirror_peer_set_client(IoCtx& io_ctx, const std::string &uuid,
644                                   const std::string &client_name) {
645     return librbd::api::Mirror<>::peer_set_client(io_ctx, uuid, client_name);
646   }
647
648   int RBD::mirror_peer_set_cluster(IoCtx& io_ctx, const std::string &uuid,
649                                    const std::string &cluster_name) {
650     return librbd::api::Mirror<>::peer_set_cluster(io_ctx, uuid, cluster_name);
651   }
652
653   int RBD::mirror_image_status_list(IoCtx& io_ctx, const std::string &start_id,
654       size_t max, std::map<std::string, mirror_image_status_t> *images) {
655     return librbd::api::Mirror<>::image_status_list(io_ctx, start_id, max,
656                                                     images);
657   }
658
659   int RBD::mirror_image_status_summary(IoCtx& io_ctx,
660       std::map<mirror_image_status_state_t, int> *states) {
661     return librbd::api::Mirror<>::image_status_summary(io_ctx, states);
662   }
663
664   RBD::AioCompletion::AioCompletion(void *cb_arg, callback_t complete_cb)
665   {
666     pc = reinterpret_cast<void*>(librbd::io::AioCompletion::create(
667       cb_arg, complete_cb, this));
668   }
669
670   bool RBD::AioCompletion::is_complete()
671   {
672     librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
673     return c->is_complete();
674   }
675
676   int RBD::AioCompletion::wait_for_complete()
677   {
678     librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
679     return c->wait_for_complete();
680   }
681
682   ssize_t RBD::AioCompletion::get_return_value()
683   {
684     librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
685     return c->get_return_value();
686   }
687
688   void *RBD::AioCompletion::get_arg()
689   {
690     librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
691     return c->get_arg();
692   }
693
694   void RBD::AioCompletion::release()
695   {
696     librbd::io::AioCompletion *c = (librbd::io::AioCompletion *)pc;
697     c->release();
698     delete this;
699   }
700
701   /*
702     ImageOptions
703   */
704
705   ImageOptions::ImageOptions()
706   {
707     librbd::image_options_create(&opts);
708   }
709
710   ImageOptions::ImageOptions(rbd_image_options_t opts_)
711   {
712     librbd::image_options_create_ref(&opts, opts_);
713   }
714
715   ImageOptions::ImageOptions(const ImageOptions &imgopts)
716   {
717     librbd::image_options_copy(&opts, imgopts);
718   }
719
720   ImageOptions::~ImageOptions()
721   {
722     librbd::image_options_destroy(opts);
723   }
724
725   int ImageOptions::set(int optname, const std::string& optval)
726   {
727     return librbd::image_options_set(opts, optname, optval);
728   }
729
730   int ImageOptions::set(int optname, uint64_t optval)
731   {
732     return librbd::image_options_set(opts, optname, optval);
733   }
734
735   int ImageOptions::get(int optname, std::string* optval) const
736   {
737     return librbd::image_options_get(opts, optname, optval);
738   }
739
740   int ImageOptions::get(int optname, uint64_t* optval) const
741   {
742     return librbd::image_options_get(opts, optname, optval);
743   }
744
745   int ImageOptions::is_set(int optname, bool* is_set)
746   {
747     return librbd::image_options_is_set(opts, optname, is_set);
748   }
749
750   int ImageOptions::unset(int optname)
751   {
752     return librbd::image_options_unset(opts, optname);
753   }
754
755   void ImageOptions::clear()
756   {
757     librbd::image_options_clear(opts);
758   }
759
760   bool ImageOptions::empty() const
761   {
762     return librbd::image_options_is_empty(opts);
763   }
764
765   /*
766     Image
767   */
768
769   Image::Image() : ctx(NULL)
770   {
771   }
772
773   Image::~Image()
774   {
775     close();
776   }
777
778   int Image::close()
779   {
780     int r = 0;
781     if (ctx) {
782       ImageCtx *ictx = (ImageCtx *)ctx;
783       tracepoint(librbd, close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
784
785       r = ictx->state->close();
786       ctx = NULL;
787
788       tracepoint(librbd, close_image_exit, r);
789     }
790     return r;
791   }
792
793   int Image::aio_close(RBD::AioCompletion *c)
794   {
795     if (!ctx) {
796       return -EINVAL;
797     }
798
799     ImageCtx *ictx = (ImageCtx *)ctx;
800     tracepoint(librbd, aio_close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), c->pc);
801
802     ictx->state->close(new C_AioCompletion(ictx, librbd::io::AIO_TYPE_CLOSE,
803                                            get_aio_completion(c)));
804     ctx = NULL;
805
806     tracepoint(librbd, aio_close_image_exit, 0);
807     return 0;
808   }
809
810   int Image::resize(uint64_t size)
811   {
812     ImageCtx *ictx = (ImageCtx *)ctx;
813     tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
814     librbd::NoOpProgressContext prog_ctx;
815     int r = ictx->operations->resize(size, true, prog_ctx);
816     tracepoint(librbd, resize_exit, r);
817     return r;
818   }
819
820   int Image::resize2(uint64_t size, bool allow_shrink, librbd::ProgressContext& pctx)
821   {
822     ImageCtx *ictx = (ImageCtx *)ctx;
823     tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
824     int r = ictx->operations->resize(size, allow_shrink, pctx);
825     tracepoint(librbd, resize_exit, r);
826     return r;
827   }
828
829   int Image::resize_with_progress(uint64_t size, librbd::ProgressContext& pctx)
830   {
831     ImageCtx *ictx = (ImageCtx *)ctx;
832     tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
833     int r = ictx->operations->resize(size, true, pctx);
834     tracepoint(librbd, resize_exit, r);
835     return r;
836   }
837
838   int Image::stat(image_info_t& info, size_t infosize)
839   {
840     ImageCtx *ictx = (ImageCtx *)ctx;
841     tracepoint(librbd, stat_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
842     int r = librbd::info(ictx, info, infosize);
843     tracepoint(librbd, stat_exit, r, &info);
844     return r;
845   }
846
847   int Image::old_format(uint8_t *old)
848   {
849     ImageCtx *ictx = (ImageCtx *)ctx;
850     tracepoint(librbd, get_old_format_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
851     int r = librbd::get_old_format(ictx, old);
852     tracepoint(librbd, get_old_format_exit, r, *old);
853     return r;
854   }
855
856   int Image::size(uint64_t *size)
857   {
858     ImageCtx *ictx = (ImageCtx *)ctx;
859     tracepoint(librbd, get_size_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
860     int r = librbd::get_size(ictx, size);
861     tracepoint(librbd, get_size_exit, r, *size);
862     return r;
863   }
864
865   int Image::features(uint64_t *features)
866   {
867     ImageCtx *ictx = (ImageCtx *)ctx;
868     tracepoint(librbd, get_features_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
869     int r = librbd::get_features(ictx, features);
870     tracepoint(librbd, get_features_exit, r, *features);
871     return r;
872   }
873
874   int Image::update_features(uint64_t features, bool enabled)
875   {
876     ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
877     tracepoint(librbd, update_features_enter, ictx, features, enabled);
878     int r = ictx->operations->update_features(features, enabled);
879     tracepoint(librbd, update_features_exit, r);
880     return r;
881   }
882
883   uint64_t Image::get_stripe_unit() const
884   {
885     ImageCtx *ictx = (ImageCtx *)ctx;
886     tracepoint(librbd, get_stripe_unit_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
887     uint64_t stripe_unit = ictx->get_stripe_unit();
888     tracepoint(librbd, get_stripe_unit_exit, 0, stripe_unit);
889     return stripe_unit;
890   }
891
892   uint64_t Image::get_stripe_count() const
893   {
894     ImageCtx *ictx = (ImageCtx *)ctx;
895     tracepoint(librbd, get_stripe_count_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
896     uint64_t stripe_count = ictx->get_stripe_count();
897     tracepoint(librbd, get_stripe_count_exit, 0, stripe_count);
898     return stripe_count;
899   }
900
901   int Image::get_create_timestamp(struct timespec *timestamp)
902   {
903     ImageCtx *ictx = (ImageCtx *)ctx;
904     tracepoint(librbd, get_create_timestamp_enter, ictx, ictx->name.c_str(),
905                ictx->read_only);
906     utime_t time = ictx->get_create_timestamp();
907     time.to_timespec(timestamp);
908     tracepoint(librbd, get_create_timestamp_exit, 0, timestamp);
909     return 0;
910   }
911
912   int Image::overlap(uint64_t *overlap)
913   {
914     ImageCtx *ictx = (ImageCtx *)ctx;
915     tracepoint(librbd, get_overlap_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
916     int r = librbd::get_overlap(ictx, overlap);
917     tracepoint(librbd, get_overlap_exit, r, *overlap);
918     return r;
919   }
920
921   int Image::get_id(std::string *id)
922   {
923     ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
924     if (ictx->old_format) {
925       return -EINVAL;
926     }
927     *id = ictx->id;
928     return 0;
929   }
930
931   std::string Image::get_block_name_prefix()
932   {
933     ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
934     return ictx->object_prefix;
935   }
936
937   int64_t Image::get_data_pool_id()
938   {
939     ImageCtx *ictx = reinterpret_cast<ImageCtx *>(ctx);
940     return ictx->data_ctx.get_id();
941   }
942
943   int Image::parent_info(string *parent_pool_name, string *parent_name,
944                          string *parent_snap_name)
945   {
946     return parent_info2(parent_pool_name, parent_name, nullptr,
947                         parent_snap_name);
948   }
949
950   int Image::parent_info2(string *parent_pool_name, string *parent_name,
951                           string *parent_id, string *parent_snap_name)
952   {
953     ImageCtx *ictx = (ImageCtx *)ctx;
954     tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
955                ictx->snap_name.c_str(), ictx->read_only);
956     int r = librbd::get_parent_info(ictx, parent_pool_name, parent_name,
957                                     parent_id, parent_snap_name);
958     tracepoint(librbd, get_parent_info_exit, r,
959                parent_pool_name ? parent_pool_name->c_str() : NULL,
960                parent_name ? parent_name->c_str() : NULL,
961                parent_id ? parent_id->c_str() : NULL,
962                parent_snap_name ? parent_snap_name->c_str() : NULL);
963     return r;
964   }
965
966   int Image::get_flags(uint64_t *flags)
967   {
968     ImageCtx *ictx = (ImageCtx *)ctx;
969     tracepoint(librbd, get_flags_enter, ictx);
970     int r = librbd::get_flags(ictx, flags);
971     tracepoint(librbd, get_flags_exit, ictx, r, *flags);
972     return r;
973   }
974
975   int Image::set_image_notification(int fd, int type)
976   {
977     ImageCtx *ictx = (ImageCtx *)ctx;
978     tracepoint(librbd, set_image_notification_enter, ictx, fd, type);
979     int r = librbd::set_image_notification(ictx, fd, type);
980     tracepoint(librbd, set_image_notification_exit, ictx, r);
981     return r;
982   }
983
984   int Image::is_exclusive_lock_owner(bool *is_owner)
985   {
986     ImageCtx *ictx = (ImageCtx *)ctx;
987     tracepoint(librbd, is_exclusive_lock_owner_enter, ictx);
988     int r = librbd::is_exclusive_lock_owner(ictx, is_owner);
989     tracepoint(librbd, is_exclusive_lock_owner_exit, ictx, r, *is_owner);
990     return r;
991   }
992
993   int Image::lock_acquire(rbd_lock_mode_t lock_mode)
994   {
995     ImageCtx *ictx = (ImageCtx *)ctx;
996     tracepoint(librbd, lock_acquire_enter, ictx, lock_mode);
997     int r = librbd::lock_acquire(ictx, lock_mode);
998     tracepoint(librbd, lock_acquire_exit, ictx, r);
999     return r;
1000   }
1001
1002   int Image::lock_release()
1003   {
1004     ImageCtx *ictx = (ImageCtx *)ctx;
1005     tracepoint(librbd, lock_release_enter, ictx);
1006     int r = librbd::lock_release(ictx);
1007     tracepoint(librbd, lock_release_exit, ictx, r);
1008     return r;
1009   }
1010
1011   int Image::lock_get_owners(rbd_lock_mode_t *lock_mode,
1012                              std::list<std::string> *lock_owners)
1013   {
1014     ImageCtx *ictx = (ImageCtx *)ctx;
1015     tracepoint(librbd, lock_get_owners_enter, ictx);
1016     int r = librbd::lock_get_owners(ictx, lock_mode, lock_owners);
1017     tracepoint(librbd, lock_get_owners_exit, ictx, r);
1018     return r;
1019   }
1020
1021   int Image::lock_break(rbd_lock_mode_t lock_mode,
1022                         const std::string &lock_owner)
1023   {
1024     ImageCtx *ictx = (ImageCtx *)ctx;
1025     tracepoint(librbd, lock_break_enter, ictx, lock_mode, lock_owner.c_str());
1026     int r = librbd::lock_break(ictx, lock_mode, lock_owner);
1027     tracepoint(librbd, lock_break_exit, ictx, r);
1028     return r;
1029   }
1030
1031   int Image::rebuild_object_map(ProgressContext &prog_ctx)
1032   {
1033     ImageCtx *ictx = reinterpret_cast<ImageCtx*>(ctx);
1034     return ictx->operations->rebuild_object_map(prog_ctx);
1035   }
1036
1037   int Image::check_object_map(ProgressContext &prog_ctx)
1038   {
1039     ImageCtx *ictx = reinterpret_cast<ImageCtx*>(ctx);
1040     return ictx->operations->check_object_map(prog_ctx);
1041   }
1042
1043   int Image::copy(IoCtx& dest_io_ctx, const char *destname)
1044   {
1045     ImageCtx *ictx = (ImageCtx *)ctx;
1046     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);
1047     ImageOptions opts;
1048     librbd::NoOpProgressContext prog_ctx;
1049     int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, 0);
1050     tracepoint(librbd, copy_exit, r);
1051     return r;
1052   }
1053
1054   int Image::copy2(Image& dest)
1055   {
1056     ImageCtx *srcctx = (ImageCtx *)ctx;
1057     ImageCtx *destctx = (ImageCtx *)dest.ctx;
1058     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);
1059     librbd::NoOpProgressContext prog_ctx;
1060     int r = librbd::copy(srcctx, destctx, prog_ctx, 0);
1061     tracepoint(librbd, copy2_exit, r);
1062     return r;
1063   }
1064
1065   int Image::copy3(IoCtx& dest_io_ctx, const char *destname, ImageOptions& opts)
1066   {
1067     ImageCtx *ictx = (ImageCtx *)ctx;
1068     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);
1069     librbd::NoOpProgressContext prog_ctx;
1070     int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, 0);
1071     tracepoint(librbd, copy3_exit, r);
1072     return r;
1073   }
1074
1075   int Image::copy4(IoCtx& dest_io_ctx, const char *destname, ImageOptions& opts, size_t sparse_size)
1076   {
1077     ImageCtx *ictx = (ImageCtx *)ctx;
1078     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);
1079     librbd::NoOpProgressContext prog_ctx;
1080     int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, sparse_size);
1081     tracepoint(librbd, copy4_exit, r);
1082     return r;
1083   }
1084
1085   int Image::copy_with_progress(IoCtx& dest_io_ctx, const char *destname,
1086                                 librbd::ProgressContext &pctx)
1087   {
1088     ImageCtx *ictx = (ImageCtx *)ctx;
1089     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);
1090     ImageOptions opts;
1091     int r = librbd::copy(ictx, dest_io_ctx, destname, opts, pctx, 0);
1092     tracepoint(librbd, copy_exit, r);
1093     return r;
1094   }
1095
1096   int Image::copy_with_progress2(Image& dest, librbd::ProgressContext &pctx)
1097   {
1098     ImageCtx *srcctx = (ImageCtx *)ctx;
1099     ImageCtx *destctx = (ImageCtx *)dest.ctx;
1100     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);
1101     int r = librbd::copy(srcctx, destctx, pctx, 0);
1102     tracepoint(librbd, copy2_exit, r);
1103     return r;
1104   }
1105
1106   int Image::copy_with_progress3(IoCtx& dest_io_ctx, const char *destname,
1107                                  ImageOptions& opts,
1108                                  librbd::ProgressContext &pctx)
1109   {
1110     ImageCtx *ictx = (ImageCtx *)ctx;
1111     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);
1112     int r = librbd::copy(ictx, dest_io_ctx, destname, opts, pctx, 0);
1113     tracepoint(librbd, copy3_exit, r);
1114     return r;
1115   }
1116
1117   int Image::copy_with_progress4(IoCtx& dest_io_ctx, const char *destname,
1118                                  ImageOptions& opts,
1119                                  librbd::ProgressContext &pctx,
1120                                  size_t sparse_size)
1121   {
1122     ImageCtx *ictx = (ImageCtx *)ctx;
1123     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);
1124     int r = librbd::copy(ictx, dest_io_ctx, destname, opts, pctx, sparse_size);
1125     tracepoint(librbd, copy4_exit, r);
1126     return r;
1127   }
1128
1129   int Image::flatten()
1130   {
1131     ImageCtx *ictx = (ImageCtx *)ctx;
1132     tracepoint(librbd, flatten_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
1133     librbd::NoOpProgressContext prog_ctx;
1134     int r = ictx->operations->flatten(prog_ctx);
1135     tracepoint(librbd, flatten_exit, r);
1136     return r;
1137   }
1138
1139   int Image::flatten_with_progress(librbd::ProgressContext& prog_ctx)
1140   {
1141     ImageCtx *ictx = (ImageCtx *)ctx;
1142     tracepoint(librbd, flatten_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
1143     int r = ictx->operations->flatten(prog_ctx);
1144     tracepoint(librbd, flatten_exit, r);
1145     return r;
1146   }
1147
1148   int Image::list_children(set<pair<string, string> > *children)
1149   {
1150     ImageCtx *ictx = (ImageCtx *)ctx;
1151     tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1152     int r = librbd::list_children(ictx, *children);
1153     if (r >= 0) {
1154       for (set<pair<string, string> >::const_iterator it = children->begin();
1155            it != children->end(); ++it) {
1156         tracepoint(librbd, list_children_entry, it->first.c_str(), it->second.c_str());
1157       }
1158     }
1159     tracepoint(librbd, list_children_exit, r);
1160     return r;
1161   }
1162
1163   int Image::list_lockers(std::list<librbd::locker_t> *lockers,
1164                           bool *exclusive, string *tag)
1165   {
1166     ImageCtx *ictx = (ImageCtx *)ctx;
1167     tracepoint(librbd, list_lockers_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1168     int r = librbd::list_lockers(ictx, lockers, exclusive, tag);
1169     if (r >= 0) {
1170       for (std::list<librbd::locker_t>::const_iterator it = lockers->begin();
1171            it != lockers->end(); ++it) {
1172         tracepoint(librbd, list_lockers_entry, it->client.c_str(), it->cookie.c_str(), it->address.c_str());
1173       }
1174     }
1175     tracepoint(librbd, list_lockers_exit, r);
1176     return r;
1177   }
1178
1179   int Image::lock_exclusive(const string& cookie)
1180   {
1181     ImageCtx *ictx = (ImageCtx *)ctx;
1182     tracepoint(librbd, lock_exclusive_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie.c_str());
1183     int r = librbd::lock(ictx, true, cookie, "");
1184     tracepoint(librbd, lock_exclusive_exit, r);
1185     return r;
1186   }
1187
1188   int Image::lock_shared(const string& cookie, const std::string& tag)
1189   {
1190     ImageCtx *ictx = (ImageCtx *)ctx;
1191     tracepoint(librbd, lock_shared_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie.c_str(), tag.c_str());
1192     int r = librbd::lock(ictx, false, cookie, tag);
1193     tracepoint(librbd, lock_shared_exit, r);
1194     return r;
1195   }
1196
1197   int Image::unlock(const string& cookie)
1198   {
1199     ImageCtx *ictx = (ImageCtx *)ctx;
1200     tracepoint(librbd, unlock_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie.c_str());
1201     int r = librbd::unlock(ictx, cookie);
1202     tracepoint(librbd, unlock_exit, r);
1203     return r;
1204   }
1205
1206   int Image::break_lock(const string& client, const string& cookie)
1207   {
1208     ImageCtx *ictx = (ImageCtx *)ctx;
1209     tracepoint(librbd, break_lock_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, client.c_str(), cookie.c_str());
1210     int r = librbd::break_lock(ictx, client, cookie);
1211     tracepoint(librbd, break_lock_exit, r);
1212     return r;
1213   }
1214
1215   int Image::snap_create(const char *snap_name)
1216   {
1217     ImageCtx *ictx = (ImageCtx *)ctx;
1218     tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1219     int r = ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
1220                                           snap_name);
1221     tracepoint(librbd, snap_create_exit, r);
1222     return r;
1223   }
1224
1225   int Image::snap_remove(const char *snap_name)
1226   {
1227     ImageCtx *ictx = (ImageCtx *)ctx;
1228     tracepoint(librbd, snap_remove_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1229     librbd::NoOpProgressContext prog_ctx;
1230     int r = librbd::snap_remove(ictx, snap_name, 0, prog_ctx);
1231     tracepoint(librbd, snap_remove_exit, r);
1232     return r;
1233   }
1234
1235   int Image::snap_remove2(const char *snap_name, uint32_t flags, ProgressContext& pctx)
1236   {
1237     ImageCtx *ictx = (ImageCtx *)ctx;
1238     tracepoint(librbd, snap_remove2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name, flags);
1239     int r = librbd::snap_remove(ictx, snap_name, flags, pctx);
1240     tracepoint(librbd, snap_remove_exit, r);
1241     return r;
1242   }
1243
1244   int Image::snap_rollback(const char *snap_name)
1245   {
1246     ImageCtx *ictx = (ImageCtx *)ctx;
1247     tracepoint(librbd, snap_rollback_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1248     librbd::NoOpProgressContext prog_ctx;
1249     int r = ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(), snap_name, prog_ctx);
1250     tracepoint(librbd, snap_rollback_exit, r);
1251     return r;
1252   }
1253
1254   int Image::snap_rename(const char *srcname, const char *dstname)
1255   {
1256     ImageCtx *ictx = (ImageCtx *)ctx;
1257     tracepoint(librbd, snap_rename_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, srcname, dstname);
1258     int r = ictx->operations->snap_rename(srcname, dstname);
1259     tracepoint(librbd, snap_rename_exit, r);
1260     return r;
1261   }
1262
1263   int Image::snap_rollback_with_progress(const char *snap_name,
1264                                          ProgressContext& prog_ctx)
1265   {
1266     ImageCtx *ictx = (ImageCtx *)ctx;
1267     tracepoint(librbd, snap_rollback_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1268     int r = ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(), snap_name, prog_ctx);
1269     tracepoint(librbd, snap_rollback_exit, r);
1270     return r;
1271   }
1272
1273   int Image::snap_protect(const char *snap_name)
1274   {
1275     ImageCtx *ictx = (ImageCtx *)ctx;
1276     tracepoint(librbd, snap_protect_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1277     int r = ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(), snap_name);
1278     tracepoint(librbd, snap_protect_exit, r);
1279     return r;
1280   }
1281
1282   int Image::snap_unprotect(const char *snap_name)
1283   {
1284     ImageCtx *ictx = (ImageCtx *)ctx;
1285     tracepoint(librbd, snap_unprotect_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1286     int r = ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(), snap_name);
1287     tracepoint(librbd, snap_unprotect_exit, r);
1288     return r;
1289   }
1290
1291   int Image::snap_is_protected(const char *snap_name, bool *is_protected)
1292   {
1293     ImageCtx *ictx = (ImageCtx *)ctx;
1294     tracepoint(librbd, snap_is_protected_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1295     int r = librbd::snap_is_protected(ictx, snap_name, is_protected);
1296     tracepoint(librbd, snap_is_protected_exit, r, *is_protected ? 1 : 0);
1297     return r;
1298   }
1299
1300   int Image::snap_list(vector<librbd::snap_info_t>& snaps)
1301   {
1302     ImageCtx *ictx = (ImageCtx *)ctx;
1303     tracepoint(librbd, snap_list_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, &snaps);
1304     int r = librbd::snap_list(ictx, snaps);
1305     if (r >= 0) {
1306       for (int i = 0, n = snaps.size(); i < n; i++) {
1307         tracepoint(librbd, snap_list_entry, snaps[i].id, snaps[i].size, snaps[i].name.c_str());
1308       }
1309     }
1310     tracepoint(librbd, snap_list_exit, r, snaps.size());
1311     if (r >= 0) {
1312       // A little ugly, but the C++ API doesn't need a Image::snap_list_end,
1313       // and we want the tracepoints to mirror the C API
1314       tracepoint(librbd, snap_list_end_enter, &snaps);
1315       tracepoint(librbd, snap_list_end_exit);
1316     }
1317     return r;
1318   }
1319
1320   bool Image::snap_exists(const char *snap_name)
1321   {
1322     ImageCtx *ictx = (ImageCtx *)ctx;
1323     tracepoint(librbd, snap_exists_enter, ictx, ictx->name.c_str(), 
1324       ictx->snap_name.c_str(), ictx->read_only, snap_name);
1325     bool exists; 
1326     int r = librbd::snap_exists(ictx, cls::rbd::UserSnapshotNamespace(), snap_name, &exists);
1327     tracepoint(librbd, snap_exists_exit, r, exists);
1328     if (r < 0) {
1329       // lie to caller since we don't know the real answer yet.
1330       return false;
1331     }
1332     return exists;
1333   }
1334
1335   // A safer verion of snap_exists.
1336   int Image::snap_exists2(const char *snap_name, bool *exists)
1337   {
1338     ImageCtx *ictx = (ImageCtx *)ctx;
1339     tracepoint(librbd, snap_exists_enter, ictx, ictx->name.c_str(), 
1340       ictx->snap_name.c_str(), ictx->read_only, snap_name);
1341     int r = librbd::snap_exists(ictx, cls::rbd::UserSnapshotNamespace(), snap_name, exists);
1342     tracepoint(librbd, snap_exists_exit, r, *exists);
1343     return r;
1344   }
1345
1346   int Image::snap_get_timestamp(uint64_t snap_id, struct timespec *timestamp)
1347   {
1348     ImageCtx *ictx = (ImageCtx *)ctx;
1349     tracepoint(librbd, snap_get_timestamp_enter, ictx, ictx->name.c_str());
1350     int r = librbd::snap_get_timestamp(ictx, snap_id, timestamp);
1351     tracepoint(librbd, snap_get_timestamp_exit, r);
1352     return r;
1353   }
1354
1355   int Image::snap_get_limit(uint64_t *limit)
1356   {
1357     ImageCtx *ictx = (ImageCtx *)ctx;
1358     tracepoint(librbd, snap_get_limit_enter, ictx, ictx->name.c_str());
1359     int r = librbd::snap_get_limit(ictx, limit);
1360     tracepoint(librbd, snap_get_limit_exit, r, *limit);
1361     return r;
1362   }
1363
1364   int Image::snap_set_limit(uint64_t limit)
1365   {
1366     ImageCtx *ictx = (ImageCtx *)ctx;
1367
1368     tracepoint(librbd, snap_set_limit_enter, ictx, ictx->name.c_str(), limit);
1369     int r = ictx->operations->snap_set_limit(limit);
1370     tracepoint(librbd, snap_set_limit_exit, r);
1371     return r;
1372   }
1373
1374   int Image::snap_set(const char *snap_name)
1375   {
1376     ImageCtx *ictx = (ImageCtx *)ctx;
1377     tracepoint(librbd, snap_set_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
1378     int r = librbd::snap_set(ictx, cls::rbd::UserSnapshotNamespace(), snap_name);
1379     tracepoint(librbd, snap_set_exit, r);
1380     return r;
1381   }
1382
1383   ssize_t Image::read(uint64_t ofs, size_t len, bufferlist& bl)
1384   {
1385     ImageCtx *ictx = (ImageCtx *)ctx;
1386     tracepoint(librbd, read_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
1387     bufferptr ptr(len);
1388     bl.push_back(std::move(ptr));
1389     int r = ictx->io_work_queue->read(ofs, len, io::ReadResult{&bl}, 0);
1390     tracepoint(librbd, read_exit, r);
1391     return r;
1392   }
1393
1394   ssize_t Image::read2(uint64_t ofs, size_t len, bufferlist& bl, int op_flags)
1395   {
1396     ImageCtx *ictx = (ImageCtx *)ctx;
1397     tracepoint(librbd, read2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
1398                 ictx->read_only, ofs, len, op_flags);
1399     bufferptr ptr(len);
1400     bl.push_back(std::move(ptr));
1401     int r = ictx->io_work_queue->read(ofs, len, io::ReadResult{&bl}, op_flags);
1402     tracepoint(librbd, read_exit, r);
1403     return r;
1404   }
1405
1406   int64_t Image::read_iterate(uint64_t ofs, size_t len,
1407                               int (*cb)(uint64_t, size_t, const char *, void *),
1408                               void *arg)
1409   {
1410     ImageCtx *ictx = (ImageCtx *)ctx;
1411     tracepoint(librbd, read_iterate_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
1412     int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg);
1413     tracepoint(librbd, read_iterate_exit, r);
1414     return r;
1415   }
1416
1417   int Image::read_iterate2(uint64_t ofs, uint64_t len,
1418                               int (*cb)(uint64_t, size_t, const char *, void *),
1419                               void *arg)
1420   {
1421     ImageCtx *ictx = (ImageCtx *)ctx;
1422     tracepoint(librbd, read_iterate2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
1423     int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg);
1424     if (r > 0)
1425       r = 0;
1426     tracepoint(librbd, read_iterate2_exit, r);
1427     return (int)r;
1428   }
1429
1430   int Image::diff_iterate(const char *fromsnapname,
1431                           uint64_t ofs, uint64_t len,
1432                           int (*cb)(uint64_t, size_t, int, void *),
1433                           void *arg)
1434   {
1435     ImageCtx *ictx = (ImageCtx *)ctx;
1436     tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(),
1437                ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len,
1438                true, false);
1439     int r = librbd::api::DiffIterate<>::diff_iterate(ictx,
1440                                                      cls::rbd::UserSnapshotNamespace(),
1441                                                      fromsnapname, ofs,
1442                                                      len, true, false, cb, arg);
1443     tracepoint(librbd, diff_iterate_exit, r);
1444     return r;
1445   }
1446
1447   int Image::diff_iterate2(const char *fromsnapname, uint64_t ofs, uint64_t len,
1448                            bool include_parent, bool whole_object,
1449                            int (*cb)(uint64_t, size_t, int, void *), void *arg)
1450   {
1451     ImageCtx *ictx = (ImageCtx *)ctx;
1452     tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(),
1453               ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len,
1454               include_parent, whole_object);
1455     int r = librbd::api::DiffIterate<>::diff_iterate(ictx,
1456                                                      cls::rbd::UserSnapshotNamespace(),
1457                                                      fromsnapname, ofs,
1458                                                      len, include_parent,
1459                                                      whole_object, cb, arg);
1460     tracepoint(librbd, diff_iterate_exit, r);
1461     return r;
1462   }
1463
1464   ssize_t Image::write(uint64_t ofs, size_t len, bufferlist& bl)
1465   {
1466     ImageCtx *ictx = (ImageCtx *)ctx;
1467     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());
1468     if (bl.length() < len) {
1469       tracepoint(librbd, write_exit, -EINVAL);
1470       return -EINVAL;
1471     }
1472     int r = ictx->io_work_queue->write(ofs, len, bufferlist{bl}, 0);
1473     tracepoint(librbd, write_exit, r);
1474     return r;
1475   }
1476
1477    ssize_t Image::write2(uint64_t ofs, size_t len, bufferlist& bl, int op_flags)
1478   {
1479     ImageCtx *ictx = (ImageCtx *)ctx;
1480     tracepoint(librbd, write2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only,
1481                 ofs, len, bl.length() < len ? NULL : bl.c_str(), op_flags);
1482     if (bl.length() < len) {
1483       tracepoint(librbd, write_exit, -EINVAL);
1484       return -EINVAL;
1485     }
1486     int r = ictx->io_work_queue->write(ofs, len, bufferlist{bl}, op_flags);
1487     tracepoint(librbd, write_exit, r);
1488     return r;
1489   }
1490
1491   int Image::discard(uint64_t ofs, uint64_t len)
1492   {
1493     ImageCtx *ictx = (ImageCtx *)ctx;
1494     tracepoint(librbd, discard_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
1495     if (len > std::numeric_limits<int32_t>::max()) {
1496         tracepoint(librbd, discard_exit, -EINVAL);
1497         return -EINVAL;
1498     }
1499     int r = ictx->io_work_queue->discard(ofs, len, ictx->skip_partial_discard);
1500     tracepoint(librbd, discard_exit, r);
1501     return r;
1502   }
1503
1504   ssize_t Image::writesame(uint64_t ofs, size_t len, bufferlist& bl, int op_flags)
1505   {
1506     ImageCtx *ictx = (ImageCtx *)ctx;
1507     tracepoint(librbd, writesame_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
1508                ictx->read_only, ofs, len, bl.length() <= 0 ? NULL : bl.c_str(), bl.length(),
1509                op_flags);
1510     if (bl.length() <= 0 || len % bl.length()) {
1511       tracepoint(librbd, writesame_exit, -EINVAL);
1512       return -EINVAL;
1513     }
1514
1515     if (mem_is_zero(bl.c_str(), bl.length())) {
1516       int r = ictx->io_work_queue->discard(ofs, len, false);
1517       tracepoint(librbd, writesame_exit, r);
1518       return r;
1519     }
1520
1521     int r = ictx->io_work_queue->writesame(ofs, len, bufferlist{bl}, op_flags);
1522     tracepoint(librbd, writesame_exit, r);
1523     return r;
1524   }
1525
1526   ssize_t Image::compare_and_write(uint64_t ofs, size_t len,
1527                                    ceph::bufferlist &cmp_bl, ceph::bufferlist& bl,
1528                                    uint64_t *mismatch_off, int op_flags)
1529   {
1530     ImageCtx *ictx = (ImageCtx *)ctx;
1531     tracepoint(librbd, compare_and_write_enter, ictx, ictx->name.c_str(),
1532                ictx->snap_name.c_str(),
1533                ictx->read_only, ofs, len, cmp_bl.length() < len ? NULL : cmp_bl.c_str(),
1534                bl.length() < len ? NULL : bl.c_str(), op_flags);
1535
1536     if (bl.length() < len) {
1537       tracepoint(librbd, write_exit, -EINVAL);
1538       return -EINVAL;
1539     }
1540
1541     int r = ictx->io_work_queue->compare_and_write(ofs, len, bufferlist{cmp_bl},
1542                                                    bufferlist{bl}, mismatch_off,
1543                                                    op_flags);
1544
1545     tracepoint(librbd, compare_and_write_exit, r);
1546
1547     return r;
1548   }
1549   int Image::aio_write(uint64_t off, size_t len, bufferlist& bl,
1550                        RBD::AioCompletion *c)
1551   {
1552     ImageCtx *ictx = (ImageCtx *)ctx;
1553     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);
1554     if (bl.length() < len) {
1555       tracepoint(librbd, aio_write_exit, -EINVAL);
1556       return -EINVAL;
1557     }
1558     ictx->io_work_queue->aio_write(get_aio_completion(c), off, len,
1559                                    bufferlist{bl}, 0);
1560     tracepoint(librbd, aio_write_exit, 0);
1561     return 0;
1562   }
1563
1564   int Image::aio_write2(uint64_t off, size_t len, bufferlist& bl,
1565                           RBD::AioCompletion *c, int op_flags)
1566   {
1567     ImageCtx *ictx = (ImageCtx *)ctx;
1568     tracepoint(librbd, aio_write2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
1569                 ictx->read_only, off, len, bl.length() < len ? NULL : bl.c_str(), c->pc, op_flags);
1570     if (bl.length() < len) {
1571       tracepoint(librbd, aio_write_exit, -EINVAL);
1572       return -EINVAL;
1573     }
1574     ictx->io_work_queue->aio_write(get_aio_completion(c), off, len,
1575                                    bufferlist{bl}, op_flags);
1576     tracepoint(librbd, aio_write_exit, 0);
1577     return 0;
1578   }
1579
1580   int Image::aio_discard(uint64_t off, uint64_t len, RBD::AioCompletion *c)
1581   {
1582     ImageCtx *ictx = (ImageCtx *)ctx;
1583     tracepoint(librbd, aio_discard_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, c->pc);
1584     ictx->io_work_queue->aio_discard(get_aio_completion(c), off, len, ictx->skip_partial_discard);
1585     tracepoint(librbd, aio_discard_exit, 0);
1586     return 0;
1587   }
1588
1589   int Image::aio_read(uint64_t off, size_t len, bufferlist& bl,
1590                       RBD::AioCompletion *c)
1591   {
1592     ImageCtx *ictx = (ImageCtx *)ctx;
1593     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);
1594     ldout(ictx->cct, 10) << "Image::aio_read() buf=" << (void *)bl.c_str() << "~"
1595                          << (void *)(bl.c_str() + len - 1) << dendl;
1596     ictx->io_work_queue->aio_read(get_aio_completion(c), off, len,
1597                                   io::ReadResult{&bl}, 0);
1598     tracepoint(librbd, aio_read_exit, 0);
1599     return 0;
1600   }
1601
1602   int Image::aio_read2(uint64_t off, size_t len, bufferlist& bl,
1603                         RBD::AioCompletion *c, int op_flags)
1604   {
1605     ImageCtx *ictx = (ImageCtx *)ctx;
1606     tracepoint(librbd, aio_read2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
1607                 ictx->read_only, off, len, bl.c_str(), c->pc, op_flags);
1608     ldout(ictx->cct, 10) << "Image::aio_read() buf=" << (void *)bl.c_str() << "~"
1609                          << (void *)(bl.c_str() + len - 1) << dendl;
1610     ictx->io_work_queue->aio_read(get_aio_completion(c), off, len,
1611                                   io::ReadResult{&bl}, op_flags);
1612     tracepoint(librbd, aio_read_exit, 0);
1613     return 0;
1614   }
1615
1616   int Image::flush()
1617   {
1618     ImageCtx *ictx = (ImageCtx *)ctx;
1619     tracepoint(librbd, flush_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1620     int r = librbd::flush(ictx);
1621     tracepoint(librbd, flush_exit, r);
1622     return r;
1623   }
1624
1625   int Image::aio_flush(RBD::AioCompletion *c)
1626   {
1627     ImageCtx *ictx = (ImageCtx *)ctx;
1628     tracepoint(librbd, aio_flush_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, c->pc);
1629     ictx->io_work_queue->aio_flush(get_aio_completion(c));
1630     tracepoint(librbd, aio_flush_exit, 0);
1631     return 0;
1632   }
1633
1634   int Image::aio_writesame(uint64_t off, size_t len, bufferlist& bl,
1635                            RBD::AioCompletion *c, int op_flags)
1636   {
1637     ImageCtx *ictx = (ImageCtx *)ctx;
1638     tracepoint(librbd, aio_writesame_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
1639                ictx->read_only, off, len, bl.length() <= len ? NULL : bl.c_str(), bl.length(),
1640                c->pc, op_flags);
1641     if (bl.length() <= 0 || len % bl.length()) {
1642       tracepoint(librbd, aio_writesame_exit, -EINVAL);
1643       return -EINVAL;
1644     }
1645
1646     if (mem_is_zero(bl.c_str(), bl.length())) {
1647       ictx->io_work_queue->aio_discard(get_aio_completion(c), off, len, false);
1648       tracepoint(librbd, aio_writesame_exit, 0);
1649       return 0;
1650     }
1651
1652     ictx->io_work_queue->aio_writesame(get_aio_completion(c), off, len,
1653                                        bufferlist{bl}, op_flags);
1654     tracepoint(librbd, aio_writesame_exit, 0);
1655     return 0;
1656   }
1657
1658   int Image::aio_compare_and_write(uint64_t off, size_t len,
1659                                    ceph::bufferlist& cmp_bl, ceph::bufferlist& bl,
1660                                    RBD::AioCompletion *c, uint64_t *mismatch_off,
1661                                    int op_flags)
1662   {
1663     ImageCtx *ictx = (ImageCtx *)ctx;
1664     tracepoint(librbd, aio_compare_and_write_enter, ictx, ictx->name.c_str(),
1665                ictx->snap_name.c_str(),
1666                ictx->read_only, off, len, cmp_bl.length() < len ? NULL : cmp_bl.c_str(),
1667                bl.length() < len ? NULL : bl.c_str(), c->pc, op_flags);
1668
1669     if (bl.length() < len) {
1670       tracepoint(librbd, compare_and_write_exit, -EINVAL);
1671       return -EINVAL;
1672     }
1673
1674     ictx->io_work_queue->aio_compare_and_write(get_aio_completion(c), off, len,
1675                                                bufferlist{cmp_bl}, bufferlist{bl},
1676                                                mismatch_off, op_flags, false);
1677
1678     tracepoint(librbd, aio_compare_and_write_exit, 0);
1679
1680     return 0;
1681   }
1682
1683   int Image::invalidate_cache()
1684   {
1685     ImageCtx *ictx = (ImageCtx *)ctx;
1686     tracepoint(librbd, invalidate_cache_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
1687     int r = librbd::invalidate_cache(ictx);
1688     tracepoint(librbd, invalidate_cache_exit, r);
1689     return r;
1690   }
1691
1692   int Image::poll_io_events(RBD::AioCompletion **comps, int numcomp)
1693   {
1694     io::AioCompletion *cs[numcomp];
1695     ImageCtx *ictx = (ImageCtx *)ctx;
1696     tracepoint(librbd, poll_io_events_enter, ictx, numcomp);
1697     int r = librbd::poll_io_events(ictx, cs, numcomp);
1698     tracepoint(librbd, poll_io_events_exit, r);
1699     if (r > 0) {
1700       for (int i = 0; i < numcomp; ++i)
1701         comps[i] = (RBD::AioCompletion *)cs[i]->rbd_comp;
1702     }
1703     return r;
1704   }
1705
1706   int Image::metadata_get(const std::string &key, std::string *value)
1707   {
1708     ImageCtx *ictx = (ImageCtx *)ctx;
1709     tracepoint(librbd, metadata_get_enter, ictx, key.c_str());
1710     int r = librbd::metadata_get(ictx, key, value);
1711     if (r < 0) {
1712       tracepoint(librbd, metadata_get_exit, r, key.c_str(), NULL);
1713     } else {
1714       tracepoint(librbd, metadata_get_exit, r, key.c_str(), value->c_str());
1715     }
1716     return r;
1717   }
1718
1719   int Image::metadata_set(const std::string &key, const std::string &value)
1720   {
1721     ImageCtx *ictx = (ImageCtx *)ctx;
1722     tracepoint(librbd, metadata_set_enter, ictx, key.c_str(), value.c_str());
1723     int r = ictx->operations->metadata_set(key, value);
1724     tracepoint(librbd, metadata_set_exit, r);
1725     return r;
1726   }
1727
1728   int Image::metadata_remove(const std::string &key)
1729   {
1730     ImageCtx *ictx = (ImageCtx *)ctx;
1731     tracepoint(librbd, metadata_remove_enter, ictx, key.c_str());
1732     int r = ictx->operations->metadata_remove(key);
1733     tracepoint(librbd, metadata_remove_exit, r);
1734     return r;
1735   }
1736
1737   int Image::metadata_list(const std::string &start, uint64_t max, map<string, bufferlist> *pairs)
1738   {
1739     ImageCtx *ictx = (ImageCtx *)ctx;
1740     tracepoint(librbd, metadata_list_enter, ictx);
1741     int r = librbd::metadata_list(ictx, start, max, pairs);
1742     if (r >= 0) {
1743       for (map<string, bufferlist>::iterator it = pairs->begin();
1744            it != pairs->end(); ++it) {
1745         tracepoint(librbd, metadata_list_entry, it->first.c_str(), it->second.c_str());
1746       }
1747     }
1748     tracepoint(librbd, metadata_list_exit, r);
1749     return r;
1750   }
1751
1752   int Image::mirror_image_enable() {
1753     ImageCtx *ictx = (ImageCtx *)ctx;
1754     return librbd::api::Mirror<>::image_enable(ictx, false);
1755   }
1756
1757   int Image::mirror_image_disable(bool force) {
1758     ImageCtx *ictx = (ImageCtx *)ctx;
1759     return librbd::api::Mirror<>::image_disable(ictx, force);
1760   }
1761
1762   int Image::mirror_image_promote(bool force) {
1763     ImageCtx *ictx = (ImageCtx *)ctx;
1764     return librbd::api::Mirror<>::image_promote(ictx, force);
1765   }
1766
1767   int Image::mirror_image_demote() {
1768     ImageCtx *ictx = (ImageCtx *)ctx;
1769     return librbd::api::Mirror<>::image_demote(ictx);
1770   }
1771
1772   int Image::mirror_image_resync()
1773   {
1774     ImageCtx *ictx = (ImageCtx *)ctx;
1775     return librbd::api::Mirror<>::image_resync(ictx);
1776   }
1777
1778   int Image::mirror_image_get_info(mirror_image_info_t *mirror_image_info,
1779                                    size_t info_size) {
1780     ImageCtx *ictx = (ImageCtx *)ctx;
1781     return librbd::api::Mirror<>::image_get_info(ictx, mirror_image_info,
1782                                                  info_size);
1783   }
1784
1785   int Image::mirror_image_get_status(mirror_image_status_t *mirror_image_status,
1786                                      size_t status_size) {
1787     ImageCtx *ictx = (ImageCtx *)ctx;
1788     return librbd::api::Mirror<>::image_get_status(ictx, mirror_image_status,
1789                                                    status_size);
1790   }
1791
1792   int Image::aio_mirror_image_promote(bool force, RBD::AioCompletion *c) {
1793     ImageCtx *ictx = (ImageCtx *)ctx;
1794     librbd::api::Mirror<>::image_promote(
1795       ictx, force, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
1796                                        get_aio_completion(c)));
1797     return 0;
1798   }
1799
1800   int Image::aio_mirror_image_demote(RBD::AioCompletion *c) {
1801     ImageCtx *ictx = (ImageCtx *)ctx;
1802     librbd::api::Mirror<>::image_demote(
1803       ictx, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
1804                                 get_aio_completion(c)));
1805     return 0;
1806   }
1807
1808   int Image::aio_mirror_image_get_info(mirror_image_info_t *mirror_image_info,
1809                                        size_t info_size,
1810                                        RBD::AioCompletion *c) {
1811     ImageCtx *ictx = (ImageCtx *)ctx;
1812     librbd::api::Mirror<>::image_get_info(
1813       ictx, mirror_image_info, info_size,
1814       new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
1815                           get_aio_completion(c)));
1816     return 0;
1817   }
1818
1819   int Image::aio_mirror_image_get_status(mirror_image_status_t *status,
1820                                          size_t status_size,
1821                                          RBD::AioCompletion *c) {
1822     ImageCtx *ictx = (ImageCtx *)ctx;
1823     librbd::api::Mirror<>::image_get_status(
1824       ictx, status, status_size,
1825       new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
1826                           get_aio_completion(c)));
1827     return 0;
1828   }
1829
1830   int Image::update_watch(UpdateWatchCtx *wctx, uint64_t *handle) {
1831     ImageCtx *ictx = (ImageCtx *)ctx;
1832     tracepoint(librbd, update_watch_enter, ictx, wctx);
1833     int r = ictx->state->register_update_watcher(wctx, handle);
1834     tracepoint(librbd, update_watch_exit, r, *handle);
1835     return r;
1836   }
1837
1838   int Image::update_unwatch(uint64_t handle) {
1839     ImageCtx *ictx = (ImageCtx *)ctx;
1840     tracepoint(librbd, update_unwatch_enter, ictx, handle);
1841     int r = ictx->state->unregister_update_watcher(handle);
1842     tracepoint(librbd, update_unwatch_exit, r);
1843     return r;
1844   }
1845
1846 } // namespace librbd
1847
1848 extern "C" void rbd_version(int *major, int *minor, int *extra)
1849 {
1850   if (major)
1851     *major = LIBRBD_VER_MAJOR;
1852   if (minor)
1853     *minor = LIBRBD_VER_MINOR;
1854   if (extra)
1855     *extra = LIBRBD_VER_EXTRA;
1856 }
1857
1858 extern "C" void rbd_image_options_create(rbd_image_options_t* opts)
1859 {
1860   librbd::image_options_create(opts);
1861 }
1862
1863 extern "C" void rbd_image_options_destroy(rbd_image_options_t opts)
1864 {
1865   librbd::image_options_destroy(opts);
1866 }
1867
1868 extern "C" int rbd_image_options_set_string(rbd_image_options_t opts, int optname,
1869                                             const char* optval)
1870 {
1871   return librbd::image_options_set(opts, optname, optval);
1872 }
1873
1874 extern "C" int rbd_image_options_set_uint64(rbd_image_options_t opts, int optname,
1875                                             uint64_t optval)
1876 {
1877   return librbd::image_options_set(opts, optname, optval);
1878 }
1879
1880 extern "C" int rbd_image_options_get_string(rbd_image_options_t opts, int optname,
1881                                             char* optval, size_t maxlen)
1882 {
1883   std::string optval_;
1884
1885   int r = librbd::image_options_get(opts, optname, &optval_);
1886
1887   if (r < 0) {
1888     return r;
1889   }
1890
1891   if (optval_.size() >= maxlen) {
1892     return -E2BIG;
1893   }
1894
1895   strncpy(optval, optval_.c_str(), maxlen);
1896
1897   return 0;
1898 }
1899
1900 extern "C" int rbd_image_options_get_uint64(rbd_image_options_t opts, int optname,
1901                                  uint64_t* optval)
1902 {
1903   return librbd::image_options_get(opts, optname, optval);
1904 }
1905
1906 extern "C" int rbd_image_options_is_set(rbd_image_options_t opts, int optname,
1907                                         bool* is_set)
1908 {
1909   return librbd::image_options_is_set(opts, optname, is_set);
1910 }
1911
1912 extern "C" int rbd_image_options_unset(rbd_image_options_t opts, int optname)
1913 {
1914   return librbd::image_options_unset(opts, optname);
1915 }
1916
1917 extern "C" void rbd_image_options_clear(rbd_image_options_t opts)
1918 {
1919   librbd::image_options_clear(opts);
1920 }
1921
1922 extern "C" int rbd_image_options_is_empty(rbd_image_options_t opts)
1923 {
1924   return librbd::image_options_is_empty(opts);
1925 }
1926
1927 /* pool mirroring */
1928 extern "C" int rbd_mirror_mode_get(rados_ioctx_t p,
1929                                    rbd_mirror_mode_t *mirror_mode) {
1930   librados::IoCtx io_ctx;
1931   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
1932   return librbd::api::Mirror<>::mode_get(io_ctx, mirror_mode);
1933 }
1934
1935 extern "C" int rbd_mirror_mode_set(rados_ioctx_t p,
1936                                    rbd_mirror_mode_t mirror_mode) {
1937   librados::IoCtx io_ctx;
1938   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
1939   return librbd::api::Mirror<>::mode_set(io_ctx, mirror_mode);
1940 }
1941
1942 extern "C" int rbd_mirror_peer_add(rados_ioctx_t p, char *uuid,
1943                                    size_t uuid_max_length,
1944                                    const char *cluster_name,
1945                                    const char *client_name) {
1946   static const std::size_t UUID_LENGTH = 36;
1947
1948   librados::IoCtx io_ctx;
1949   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
1950
1951   if (uuid_max_length < UUID_LENGTH + 1) {
1952     return -E2BIG;
1953   }
1954
1955   std::string uuid_str;
1956   int r = librbd::api::Mirror<>::peer_add(io_ctx, &uuid_str, cluster_name,
1957                                           client_name);
1958   if (r >= 0) {
1959     strncpy(uuid, uuid_str.c_str(), uuid_max_length);
1960     uuid[uuid_max_length - 1] = '\0';
1961   }
1962   return r;
1963 }
1964
1965 extern "C" int rbd_mirror_peer_remove(rados_ioctx_t p, const char *uuid) {
1966   librados::IoCtx io_ctx;
1967   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
1968   int r = librbd::api::Mirror<>::peer_remove(io_ctx, uuid);
1969   return r;
1970 }
1971
1972 extern "C" int rbd_mirror_peer_list(rados_ioctx_t p,
1973                                     rbd_mirror_peer_t *peers, int *max_peers) {
1974   librados::IoCtx io_ctx;
1975   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
1976
1977   std::vector<librbd::mirror_peer_t> peer_vector;
1978   int r = librbd::api::Mirror<>::peer_list(io_ctx, &peer_vector);
1979   if (r < 0) {
1980     return r;
1981   }
1982
1983   if (*max_peers < static_cast<int>(peer_vector.size())) {
1984     *max_peers = static_cast<int>(peer_vector.size());
1985     return -ERANGE;
1986   }
1987
1988   for (int i = 0; i < static_cast<int>(peer_vector.size()); ++i) {
1989     peers[i].uuid = strdup(peer_vector[i].uuid.c_str());
1990     peers[i].cluster_name = strdup(peer_vector[i].cluster_name.c_str());
1991     peers[i].client_name = strdup(peer_vector[i].client_name.c_str());
1992   }
1993   *max_peers = static_cast<int>(peer_vector.size());
1994   return 0;
1995 }
1996
1997 extern "C" void rbd_mirror_peer_list_cleanup(rbd_mirror_peer_t *peers,
1998                                              int max_peers) {
1999   for (int i = 0; i < max_peers; ++i) {
2000     free(peers[i].uuid);
2001     free(peers[i].cluster_name);
2002     free(peers[i].client_name);
2003   }
2004 }
2005
2006 extern "C" int rbd_mirror_peer_set_client(rados_ioctx_t p, const char *uuid,
2007                                           const char *client_name) {
2008   librados::IoCtx io_ctx;
2009   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2010   return librbd::api::Mirror<>::peer_set_client(io_ctx, uuid, client_name);
2011 }
2012
2013 extern "C" int rbd_mirror_peer_set_cluster(rados_ioctx_t p, const char *uuid,
2014                                            const char *cluster_name) {
2015   librados::IoCtx io_ctx;
2016   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2017   return librbd::api::Mirror<>::peer_set_cluster(io_ctx, uuid, cluster_name);
2018 }
2019
2020 extern "C" int rbd_mirror_image_status_list(rados_ioctx_t p,
2021     const char *start_id, size_t max, char **image_ids,
2022     rbd_mirror_image_status_t *images, size_t *len) {
2023   librados::IoCtx io_ctx;
2024   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2025   std::map<std::string, librbd::mirror_image_status_t> cpp_images;
2026
2027   int r = librbd::api::Mirror<>::image_status_list(io_ctx, start_id, max,
2028                                                    &cpp_images);
2029   if (r < 0) {
2030     return r;
2031   }
2032
2033   size_t i = 0;
2034   for (auto &it : cpp_images) {
2035     assert(i < max);
2036     const std::string &image_id = it.first;
2037     image_ids[i] = strdup(image_id.c_str());
2038     mirror_image_status_cpp_to_c(it.second, &images[i]);
2039     i++;
2040   }
2041   *len = i;
2042   return 0;
2043 }
2044
2045 extern "C" void rbd_mirror_image_status_list_cleanup(char **image_ids,
2046     rbd_mirror_image_status_t *images, size_t len) {
2047   for (size_t i = 0; i < len; i++) {
2048     free(image_ids[i]);
2049     free(images[i].name);
2050     free(images[i].info.global_id);
2051     free(images[i].description);
2052   }
2053 }
2054
2055 extern "C" int rbd_mirror_image_status_summary(rados_ioctx_t p,
2056     rbd_mirror_image_status_state_t *states, int *counts, size_t *maxlen) {
2057
2058   librados::IoCtx io_ctx;
2059   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2060
2061   std::map<librbd::mirror_image_status_state_t, int> states_;
2062   int r = librbd::api::Mirror<>::image_status_summary(io_ctx, &states_);
2063   if (r < 0) {
2064     return r;
2065   }
2066
2067   size_t i = 0;
2068   for (auto &it : states_) {
2069     if (i == *maxlen) {
2070       return -ERANGE;
2071     }
2072     states[i] = it.first;
2073     counts[i] = it.second;
2074     i++;
2075   }
2076   *maxlen = i;
2077   return 0;
2078 }
2079
2080 /* images */
2081 extern "C" int rbd_list(rados_ioctx_t p, char *names, size_t *size)
2082 {
2083   librados::IoCtx io_ctx;
2084   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2085   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2086   tracepoint(librbd, list_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id());
2087   vector<string> cpp_names;
2088   int r = librbd::list(io_ctx, cpp_names);
2089   if (r < 0) {
2090     tracepoint(librbd, list_exit, r, *size);
2091     return r;
2092   }
2093
2094   size_t expected_size = 0;
2095
2096   for (size_t i = 0; i < cpp_names.size(); i++) {
2097     expected_size += cpp_names[i].size() + 1;
2098   }
2099   if (*size < expected_size) {
2100     *size = expected_size;
2101     tracepoint(librbd, list_exit, -ERANGE, *size);
2102     return -ERANGE;
2103   }
2104
2105   if (!names) 
2106     return -EINVAL;
2107
2108   for (int i = 0; i < (int)cpp_names.size(); i++) {
2109     const char* name = cpp_names[i].c_str();
2110     tracepoint(librbd, list_entry, name);
2111     strcpy(names, name);
2112     names += strlen(names) + 1;
2113   }
2114   tracepoint(librbd, list_exit, (int)expected_size, *size);
2115   return (int)expected_size;
2116 }
2117
2118 extern "C" int rbd_create(rados_ioctx_t p, const char *name, uint64_t size, int *order)
2119 {
2120   librados::IoCtx io_ctx;
2121   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2122   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2123   tracepoint(librbd, create_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, *order);
2124   int r = librbd::create(io_ctx, name, size, order);
2125   tracepoint(librbd, create_exit, r, *order);
2126   return r;
2127 }
2128
2129 extern "C" int rbd_create2(rados_ioctx_t p, const char *name,
2130                            uint64_t size, uint64_t features,
2131                            int *order)
2132 {
2133   librados::IoCtx io_ctx;
2134   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2135   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2136   tracepoint(librbd, create2_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, features, *order);
2137   int r = librbd::create(io_ctx, name, size, false, features, order, 0, 0);
2138   tracepoint(librbd, create2_exit, r, *order);
2139   return r;
2140 }
2141
2142 extern "C" int rbd_create3(rados_ioctx_t p, const char *name,
2143                            uint64_t size, uint64_t features,
2144                            int *order,
2145                            uint64_t stripe_unit, uint64_t stripe_count)
2146 {
2147   librados::IoCtx io_ctx;
2148   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2149   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2150   tracepoint(librbd, create3_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, features, *order, stripe_unit, stripe_count);
2151   int r = librbd::create(io_ctx, name, size, false, features, order,
2152                         stripe_unit, stripe_count);
2153   tracepoint(librbd, create3_exit, r, *order);
2154   return r;
2155 }
2156
2157 extern "C" int rbd_create4(rados_ioctx_t p, const char *name,
2158                            uint64_t size, rbd_image_options_t opts)
2159 {
2160   librados::IoCtx io_ctx;
2161   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2162   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2163   tracepoint(librbd, create4_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name, size, opts);
2164   librbd::ImageOptions opts_(opts);
2165   int r = librbd::create(io_ctx, name, "", size, opts_, "", "", false);
2166   tracepoint(librbd, create4_exit, r);
2167   return r;
2168 }
2169
2170 extern "C" int rbd_clone(rados_ioctx_t p_ioctx, const char *p_name,
2171                          const char *p_snap_name, rados_ioctx_t c_ioctx,
2172                          const char *c_name, uint64_t features, int *c_order)
2173 {
2174   librados::IoCtx p_ioc, c_ioc;
2175   librados::IoCtx::from_rados_ioctx_t(p_ioctx, p_ioc);
2176   librados::IoCtx::from_rados_ioctx_t(c_ioctx, c_ioc);
2177   TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioc));
2178   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);
2179   int r = librbd::clone(p_ioc, p_name, p_snap_name, c_ioc, c_name,
2180                        features, c_order, 0, 0);
2181   tracepoint(librbd, clone_exit, r, *c_order);
2182   return r;
2183 }
2184
2185 extern "C" int rbd_clone2(rados_ioctx_t p_ioctx, const char *p_name,
2186                           const char *p_snap_name, rados_ioctx_t c_ioctx,
2187                           const char *c_name, uint64_t features, int *c_order,
2188                           uint64_t stripe_unit, int stripe_count)
2189 {
2190   librados::IoCtx p_ioc, c_ioc;
2191   librados::IoCtx::from_rados_ioctx_t(p_ioctx, p_ioc);
2192   librados::IoCtx::from_rados_ioctx_t(c_ioctx, c_ioc);
2193   TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioc));
2194   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);
2195   int r = librbd::clone(p_ioc, p_name, p_snap_name, c_ioc, c_name,
2196                        features, c_order, stripe_unit, stripe_count);
2197   tracepoint(librbd, clone2_exit, r, *c_order);
2198   return r;
2199 }
2200
2201 extern "C" int rbd_clone3(rados_ioctx_t p_ioctx, const char *p_name,
2202                           const char *p_snap_name, rados_ioctx_t c_ioctx,
2203                           const char *c_name, rbd_image_options_t c_opts)
2204 {
2205   librados::IoCtx p_ioc, c_ioc;
2206   librados::IoCtx::from_rados_ioctx_t(p_ioctx, p_ioc);
2207   librados::IoCtx::from_rados_ioctx_t(c_ioctx, c_ioc);
2208   TracepointProvider::initialize<tracepoint_traits>(get_cct(p_ioc));
2209   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);
2210   librbd::ImageOptions c_opts_(c_opts);
2211   int r = librbd::clone(p_ioc, p_name, p_snap_name, c_ioc, c_name, c_opts_);
2212   tracepoint(librbd, clone3_exit, r);
2213   return r;
2214 }
2215
2216 extern "C" int rbd_remove(rados_ioctx_t p, const char *name)
2217 {
2218   librados::IoCtx io_ctx;
2219   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2220   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2221   tracepoint(librbd, remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name);
2222   librbd::NoOpProgressContext prog_ctx;
2223   int r = librbd::remove(io_ctx, name, "", prog_ctx);
2224   tracepoint(librbd, remove_exit, r);
2225   return r;
2226 }
2227
2228 extern "C" int rbd_remove_with_progress(rados_ioctx_t p, const char *name,
2229                                         librbd_progress_fn_t cb, void *cbdata)
2230 {
2231   librados::IoCtx io_ctx;
2232   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2233   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2234   tracepoint(librbd, remove_enter, io_ctx.get_pool_name().c_str(), io_ctx.get_id(), name);
2235   librbd::CProgressContext prog_ctx(cb, cbdata);
2236   int r = librbd::remove(io_ctx, name, "", prog_ctx);
2237   tracepoint(librbd, remove_exit, r);
2238   return r;
2239 }
2240
2241 extern "C" int rbd_trash_move(rados_ioctx_t p, const char *name,
2242                               uint64_t delay) {
2243   librados::IoCtx io_ctx;
2244   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2245   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2246   tracepoint(librbd, trash_move_enter, io_ctx.get_pool_name().c_str(),
2247              io_ctx.get_id(), name);
2248   int r = librbd::trash_move(io_ctx, RBD_TRASH_IMAGE_SOURCE_USER, name, delay);
2249   tracepoint(librbd, trash_move_exit, r);
2250   return r;
2251 }
2252
2253 extern "C" int rbd_trash_get(rados_ioctx_t io, const char *id,
2254                              rbd_trash_image_info_t *info) {
2255   librados::IoCtx io_ctx;
2256   librados::IoCtx::from_rados_ioctx_t(io, io_ctx);
2257
2258   librbd::trash_image_info_t cpp_info;
2259   int r = librbd::trash_get(io_ctx, id, &cpp_info);
2260   if (r < 0) {
2261     return r;
2262   }
2263
2264   trash_image_info_cpp_to_c(cpp_info, info);
2265   return 0;
2266 }
2267
2268 extern "C" void rbd_trash_get_cleanup(rbd_trash_image_info_t *info) {
2269   free(info->id);
2270   free(info->name);
2271 }
2272
2273 extern "C" int rbd_trash_list(rados_ioctx_t p, rbd_trash_image_info_t *entries,
2274                               size_t *num_entries) {
2275   librados::IoCtx io_ctx;
2276   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2277   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2278   tracepoint(librbd, trash_list_enter,
2279              io_ctx.get_pool_name().c_str(), io_ctx.get_id());
2280
2281   vector<librbd::trash_image_info_t> cpp_entries;
2282   int r = librbd::trash_list(io_ctx, cpp_entries);
2283   if (r < 0) {
2284     tracepoint(librbd, trash_list_exit, r, *num_entries);
2285     return r;
2286   }
2287
2288   if (*num_entries < cpp_entries.size()) {
2289     *num_entries = cpp_entries.size();
2290     tracepoint(librbd, trash_list_exit, -ERANGE, *num_entries);
2291     return -ERANGE;
2292   }
2293
2294   int i=0;
2295   for (const auto &entry : cpp_entries) {
2296     trash_image_info_cpp_to_c(entry, &entries[i++]);
2297   }
2298   *num_entries = cpp_entries.size();
2299
2300   return *num_entries;
2301 }
2302
2303 extern "C" void rbd_trash_list_cleanup(rbd_trash_image_info_t *entries,
2304                                        size_t num_entries) {
2305   for (size_t i=0; i < num_entries; i++) {
2306     rbd_trash_get_cleanup(&entries[i]);
2307   }
2308 }
2309
2310 extern "C" int rbd_trash_remove(rados_ioctx_t p, const char *image_id,
2311                                 bool force) {
2312   librados::IoCtx io_ctx;
2313   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2314   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2315   tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
2316              io_ctx.get_id(), image_id, force);
2317   librbd::NoOpProgressContext prog_ctx;
2318   int r = librbd::trash_remove(io_ctx, image_id, force, prog_ctx);
2319   tracepoint(librbd, trash_remove_exit, r);
2320   return r;
2321 }
2322
2323 extern "C" int rbd_trash_remove_with_progress(rados_ioctx_t p,
2324                                               const char *image_id,
2325                                               bool force,
2326                                               librbd_progress_fn_t cb,
2327                                               void *cbdata) {
2328   librados::IoCtx io_ctx;
2329   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2330   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2331   tracepoint(librbd, trash_remove_enter, io_ctx.get_pool_name().c_str(),
2332              io_ctx.get_id(), image_id, force);
2333   librbd::CProgressContext prog_ctx(cb, cbdata);
2334   int r = librbd::trash_remove(io_ctx, image_id, force, prog_ctx);
2335   tracepoint(librbd, trash_remove_exit, r);
2336   return r;
2337 }
2338
2339 extern "C" int rbd_trash_restore(rados_ioctx_t p, const char *id,
2340                                  const char *name) {
2341   librados::IoCtx io_ctx;
2342   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2343   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2344   tracepoint(librbd, trash_undelete_enter, io_ctx.get_pool_name().c_str(),
2345              io_ctx.get_id(), id, name);
2346   int r = librbd::trash_restore(io_ctx, id, name);
2347   tracepoint(librbd, trash_undelete_exit, r);
2348   return r;
2349 }
2350
2351 extern "C" int rbd_copy(rbd_image_t image, rados_ioctx_t dest_p,
2352                         const char *destname)
2353 {
2354   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2355   librados::IoCtx dest_io_ctx;
2356   librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
2357   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);
2358   librbd::ImageOptions opts;
2359   librbd::NoOpProgressContext prog_ctx;
2360   int r = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, 0);
2361   tracepoint(librbd, copy_exit, r);
2362   return r;
2363 }
2364
2365 extern "C" int rbd_copy2(rbd_image_t srcp, rbd_image_t destp)
2366 {
2367   librbd::ImageCtx *src = (librbd::ImageCtx *)srcp;
2368   librbd::ImageCtx *dest = (librbd::ImageCtx *)destp;
2369   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);
2370   librbd::NoOpProgressContext prog_ctx;
2371   int r = librbd::copy(src, dest, prog_ctx, 0);
2372   tracepoint(librbd, copy2_exit, r);
2373   return r;
2374 }
2375
2376 extern "C" int rbd_copy3(rbd_image_t image, rados_ioctx_t dest_p,
2377                          const char *destname, rbd_image_options_t c_opts)
2378 {
2379   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2380   librados::IoCtx dest_io_ctx;
2381   librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
2382   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);
2383   librbd::ImageOptions c_opts_(c_opts);
2384   librbd::NoOpProgressContext prog_ctx;
2385   int r = librbd::copy(ictx, dest_io_ctx, destname, c_opts_, prog_ctx, 0);
2386   tracepoint(librbd, copy3_exit, r);
2387   return r;
2388 }
2389
2390 extern "C" int rbd_copy4(rbd_image_t image, rados_ioctx_t dest_p,
2391                          const char *destname, rbd_image_options_t c_opts, size_t sparse_size)
2392 {
2393   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2394   librados::IoCtx dest_io_ctx;
2395   librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
2396   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);
2397   librbd::ImageOptions c_opts_(c_opts);
2398   librbd::NoOpProgressContext prog_ctx;
2399   int r = librbd::copy(ictx, dest_io_ctx, destname, c_opts_, prog_ctx, sparse_size);
2400   tracepoint(librbd, copy4_exit, r);
2401   return r;
2402 }
2403
2404 extern "C" int rbd_copy_with_progress(rbd_image_t image, rados_ioctx_t dest_p,
2405                                       const char *destname,
2406                                       librbd_progress_fn_t fn, void *data)
2407 {
2408   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2409   librados::IoCtx dest_io_ctx;
2410   librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
2411   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);
2412   librbd::ImageOptions opts;
2413   librbd::CProgressContext prog_ctx(fn, data);
2414   int ret = librbd::copy(ictx, dest_io_ctx, destname, opts, prog_ctx, 0);
2415   tracepoint(librbd, copy_exit, ret);
2416   return ret;
2417 }
2418
2419 extern "C" int rbd_copy_with_progress2(rbd_image_t srcp, rbd_image_t destp,
2420                                       librbd_progress_fn_t fn, void *data)
2421 {
2422   librbd::ImageCtx *src = (librbd::ImageCtx *)srcp;
2423   librbd::ImageCtx *dest = (librbd::ImageCtx *)destp;
2424   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);
2425   librbd::CProgressContext prog_ctx(fn, data);
2426   int ret = librbd::copy(src, dest, prog_ctx, 0);
2427   tracepoint(librbd, copy2_exit, ret);
2428   return ret;
2429 }
2430
2431 extern "C" int rbd_copy_with_progress3(rbd_image_t image, rados_ioctx_t dest_p,
2432                                        const char *destname,
2433                                        rbd_image_options_t dest_opts,
2434                                        librbd_progress_fn_t fn, void *data)
2435 {
2436   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2437   librados::IoCtx dest_io_ctx;
2438   librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
2439   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);
2440   librbd::ImageOptions dest_opts_(dest_opts);
2441   librbd::CProgressContext prog_ctx(fn, data);
2442   int ret = librbd::copy(ictx, dest_io_ctx, destname, dest_opts_, prog_ctx, 0);
2443   tracepoint(librbd, copy3_exit, ret);
2444   return ret;
2445 }
2446
2447 extern "C" int rbd_copy_with_progress4(rbd_image_t image, rados_ioctx_t dest_p,
2448                                        const char *destname,
2449                                        rbd_image_options_t dest_opts,
2450                                        librbd_progress_fn_t fn, void *data, size_t sparse_size)
2451 {
2452   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2453   librados::IoCtx dest_io_ctx;
2454   librados::IoCtx::from_rados_ioctx_t(dest_p, dest_io_ctx);
2455   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);
2456   librbd::ImageOptions dest_opts_(dest_opts);
2457   librbd::CProgressContext prog_ctx(fn, data);
2458   int ret = librbd::copy(ictx, dest_io_ctx, destname, dest_opts_, prog_ctx, sparse_size);
2459   tracepoint(librbd, copy4_exit, ret);
2460   return ret;
2461 }
2462
2463
2464 extern "C" int rbd_flatten(rbd_image_t image)
2465 {
2466   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2467   tracepoint(librbd, flatten_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
2468   librbd::NoOpProgressContext prog_ctx;
2469   int r = ictx->operations->flatten(prog_ctx);
2470   tracepoint(librbd, flatten_exit, r);
2471   return r;
2472 }
2473
2474 extern "C" int rbd_flatten_with_progress(rbd_image_t image,
2475                                          librbd_progress_fn_t cb, void *cbdata)
2476 {
2477   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2478   tracepoint(librbd, flatten_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
2479   librbd::CProgressContext prog_ctx(cb, cbdata);
2480   int r = ictx->operations->flatten(prog_ctx);
2481   tracepoint(librbd, flatten_exit, r);
2482   return r;
2483 }
2484
2485 extern "C" int rbd_rename(rados_ioctx_t src_p, const char *srcname,
2486                           const char *destname)
2487 {
2488   librados::IoCtx src_io_ctx;
2489   librados::IoCtx::from_rados_ioctx_t(src_p, src_io_ctx);
2490   TracepointProvider::initialize<tracepoint_traits>(get_cct(src_io_ctx));
2491   tracepoint(librbd, rename_enter, src_io_ctx.get_pool_name().c_str(), src_io_ctx.get_id(), srcname, destname);
2492   int r = librbd::rename(src_io_ctx, srcname, destname);
2493   tracepoint(librbd, rename_exit, r);
2494   return r;
2495 }
2496
2497 extern "C" int rbd_open(rados_ioctx_t p, const char *name, rbd_image_t *image,
2498                         const char *snap_name)
2499 {
2500   librados::IoCtx io_ctx;
2501   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2502   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2503   librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx,
2504                                                 false);
2505   tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2506
2507   int r = ictx->state->open(false);
2508   if (r >= 0) {
2509     *image = (rbd_image_t)ictx;
2510   }
2511   tracepoint(librbd, open_image_exit, r);
2512   return r;
2513 }
2514
2515 extern "C" int rbd_open_by_id(rados_ioctx_t p, const char *id,
2516                               rbd_image_t *image, const char *snap_name)
2517 {
2518   librados::IoCtx io_ctx;
2519   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2520   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2521   librbd::ImageCtx *ictx = new librbd::ImageCtx("", id, snap_name, io_ctx,
2522                                                 false);
2523   tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(),
2524              ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2525
2526   int r = ictx->state->open(false);
2527   if (r < 0) {
2528     delete ictx;
2529   } else {
2530     *image = (rbd_image_t)ictx;
2531   }
2532   tracepoint(librbd, open_image_exit, r);
2533   return r;
2534 }
2535
2536 extern "C" int rbd_aio_open(rados_ioctx_t p, const char *name,
2537                             rbd_image_t *image, const char *snap_name,
2538                             rbd_completion_t c)
2539 {
2540   librados::IoCtx io_ctx;
2541   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2542   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2543   librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx,
2544                                                 false);
2545   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
2546   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);
2547   ictx->state->open(false, new C_OpenComplete(ictx, get_aio_completion(comp), image));
2548   tracepoint(librbd, aio_open_image_exit, 0);
2549   return 0;
2550 }
2551
2552 extern "C" int rbd_aio_open_by_id(rados_ioctx_t p, const char *id,
2553                                   rbd_image_t *image, const char *snap_name,
2554                                   rbd_completion_t c)
2555 {
2556   librados::IoCtx io_ctx;
2557   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2558   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2559   librbd::ImageCtx *ictx = new librbd::ImageCtx("", id, snap_name, io_ctx,
2560                                                 false);
2561   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
2562   tracepoint(librbd, aio_open_image_enter, ictx, ictx->name.c_str(),
2563              ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only,
2564              comp->pc);
2565   ictx->state->open(false, new C_OpenComplete(ictx, get_aio_completion(comp), image));
2566   tracepoint(librbd, aio_open_image_exit, 0);
2567   return 0;
2568 }
2569
2570 extern "C" int rbd_open_read_only(rados_ioctx_t p, const char *name,
2571                                   rbd_image_t *image, const char *snap_name)
2572 {
2573   librados::IoCtx io_ctx;
2574   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2575   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2576   librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx,
2577                                                 true);
2578   tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2579
2580   int r = ictx->state->open(false);
2581   if (r >= 0) {
2582     *image = (rbd_image_t)ictx;
2583   }
2584   tracepoint(librbd, open_image_exit, r);
2585   return r;
2586 }
2587
2588 extern "C" int rbd_open_by_id_read_only(rados_ioctx_t p, const char *id,
2589                                         rbd_image_t *image, const char *snap_name)
2590 {
2591   librados::IoCtx io_ctx;
2592   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2593   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2594   librbd::ImageCtx *ictx = new librbd::ImageCtx("", id, snap_name, io_ctx,
2595                                                 true);
2596   tracepoint(librbd, open_image_enter, ictx, ictx->name.c_str(),
2597              ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2598
2599   int r = ictx->state->open(false);
2600   if (r < 0) {
2601     delete ictx;
2602   } else {
2603     *image = (rbd_image_t)ictx;
2604   }
2605   tracepoint(librbd, open_image_exit, r);
2606   return r;
2607 }
2608
2609 extern "C" int rbd_aio_open_read_only(rados_ioctx_t p, const char *name,
2610                                       rbd_image_t *image, const char *snap_name,
2611                                       rbd_completion_t c)
2612 {
2613   librados::IoCtx io_ctx;
2614   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2615   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2616   librbd::ImageCtx *ictx = new librbd::ImageCtx(name, "", snap_name, io_ctx,
2617                                                 true);
2618   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
2619   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);
2620   ictx->state->open(false, new C_OpenComplete(ictx, get_aio_completion(comp),
2621                                               image));
2622   tracepoint(librbd, aio_open_image_exit, 0);
2623   return 0;
2624 }
2625
2626 extern "C" int rbd_aio_open_by_id_read_only(rados_ioctx_t p, const char *id,
2627                                             rbd_image_t *image,
2628                                             const char *snap_name,
2629                                             rbd_completion_t c)
2630 {
2631   librados::IoCtx io_ctx;
2632   librados::IoCtx::from_rados_ioctx_t(p, io_ctx);
2633   TracepointProvider::initialize<tracepoint_traits>(get_cct(io_ctx));
2634   librbd::ImageCtx *ictx = new librbd::ImageCtx("", id, snap_name, io_ctx,
2635                                                 true);
2636   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
2637   tracepoint(librbd, aio_open_image_enter, ictx, ictx->name.c_str(),
2638              ictx->id.c_str(), ictx->snap_name.c_str(), ictx->read_only, comp->pc);
2639   ictx->state->open(false, new C_OpenComplete(ictx, get_aio_completion(comp),
2640                                               image));
2641   tracepoint(librbd, aio_open_image_exit, 0);
2642   return 0;
2643 }
2644
2645 extern "C" int rbd_close(rbd_image_t image)
2646 {
2647   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2648   tracepoint(librbd, close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str());
2649
2650   int r = ictx->state->close();
2651
2652   tracepoint(librbd, close_image_exit, r);
2653   return r;
2654 }
2655
2656 extern "C" int rbd_aio_close(rbd_image_t image, rbd_completion_t c)
2657 {
2658   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2659   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
2660   tracepoint(librbd, aio_close_image_enter, ictx, ictx->name.c_str(), ictx->id.c_str(), comp->pc);
2661   ictx->state->close(new C_AioCompletion(ictx, librbd::io::AIO_TYPE_CLOSE,
2662                                          get_aio_completion(comp)));
2663   tracepoint(librbd, aio_close_image_exit, 0);
2664   return 0;
2665 }
2666
2667 extern "C" int rbd_resize(rbd_image_t image, uint64_t size)
2668 {
2669   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2670   tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
2671   librbd::NoOpProgressContext prog_ctx;
2672   int r = ictx->operations->resize(size, true, prog_ctx);
2673   tracepoint(librbd, resize_exit, r);
2674   return r;
2675 }
2676
2677 extern "C" int rbd_resize2(rbd_image_t image, uint64_t size, bool allow_shrink,
2678                                         librbd_progress_fn_t cb, void *cbdata)
2679 {
2680   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2681   tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
2682   librbd::CProgressContext prog_ctx(cb, cbdata);
2683   int r = ictx->operations->resize(size, allow_shrink, prog_ctx);
2684   tracepoint(librbd, resize_exit, r);
2685   return r;
2686 }
2687
2688 extern "C" int rbd_resize_with_progress(rbd_image_t image, uint64_t size,
2689                                         librbd_progress_fn_t cb, void *cbdata)
2690 {
2691   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2692   tracepoint(librbd, resize_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, size);
2693   librbd::CProgressContext prog_ctx(cb, cbdata);
2694   int r = ictx->operations->resize(size, true, prog_ctx);
2695   tracepoint(librbd, resize_exit, r);
2696   return r;
2697 }
2698
2699 extern "C" int rbd_stat(rbd_image_t image, rbd_image_info_t *info,
2700                         size_t infosize)
2701 {
2702   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2703   tracepoint(librbd, stat_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2704   int r = librbd::info(ictx, *info, infosize);
2705   tracepoint(librbd, stat_exit, r, info);
2706   return r;
2707 }
2708
2709 extern "C" int rbd_get_old_format(rbd_image_t image, uint8_t *old)
2710 {
2711   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2712   tracepoint(librbd, get_old_format_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2713   int r = librbd::get_old_format(ictx, old);
2714   tracepoint(librbd, get_old_format_exit, r, *old);
2715   return r;
2716 }
2717
2718 extern "C" int rbd_get_size(rbd_image_t image, uint64_t *size)
2719 {
2720   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2721   tracepoint(librbd, get_size_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2722   int r = librbd::get_size(ictx, size);
2723   tracepoint(librbd, get_size_exit, r, *size);
2724   return r;
2725 }
2726
2727 extern "C" int rbd_get_features(rbd_image_t image, uint64_t *features)
2728 {
2729   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2730   tracepoint(librbd, get_features_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2731   int r = librbd::get_features(ictx, features);
2732   tracepoint(librbd, get_features_exit, r, *features);
2733   return r;
2734 }
2735
2736 extern "C" int rbd_update_features(rbd_image_t image, uint64_t features,
2737                                   uint8_t enabled)
2738 {
2739   librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
2740   bool features_enabled = enabled != 0;
2741   tracepoint(librbd, update_features_enter, ictx, features, features_enabled);
2742   int r = ictx->operations->update_features(features, features_enabled);
2743   tracepoint(librbd, update_features_exit, r);
2744   return r;
2745 }
2746
2747 extern "C" int rbd_get_stripe_unit(rbd_image_t image, uint64_t *stripe_unit)
2748 {
2749   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2750   tracepoint(librbd, get_stripe_unit_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2751   *stripe_unit = ictx->get_stripe_unit();
2752   tracepoint(librbd, get_stripe_unit_exit, 0, *stripe_unit);
2753   return 0;
2754 }
2755
2756 extern "C" int rbd_get_stripe_count(rbd_image_t image, uint64_t *stripe_count)
2757 {
2758   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2759   tracepoint(librbd, get_stripe_count_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2760   *stripe_count = ictx->get_stripe_count();
2761   tracepoint(librbd, get_stripe_count_exit, 0, *stripe_count);
2762   return 0;
2763 }
2764
2765 extern "C"  int rbd_get_create_timestamp(rbd_image_t image,
2766                                            struct timespec *timestamp)
2767 {
2768   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2769   tracepoint(librbd, get_create_timestamp_enter, ictx, ictx->name.c_str(),
2770              ictx->read_only);
2771   utime_t time = ictx->get_create_timestamp();
2772   time.to_timespec(timestamp);
2773   tracepoint(librbd, get_create_timestamp_exit, 0, timestamp);
2774   return 0;
2775 }
2776
2777 extern "C" int rbd_get_overlap(rbd_image_t image, uint64_t *overlap)
2778 {
2779   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2780   tracepoint(librbd, get_overlap_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
2781   int r = librbd::get_overlap(ictx, overlap);
2782   tracepoint(librbd, get_overlap_exit, r, *overlap);
2783   return r;
2784 }
2785
2786 extern "C" int rbd_get_id(rbd_image_t image, char *id, size_t id_len)
2787 {
2788   librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
2789   if (ictx->old_format) {
2790     return -EINVAL;
2791   }
2792   if (ictx->id.size() >= id_len) {
2793     return -ERANGE;
2794   }
2795
2796   strncpy(id, ictx->id.c_str(), id_len - 1);
2797   id[id_len - 1] = '\0';
2798   return 0;
2799 }
2800
2801 extern "C" int rbd_get_block_name_prefix(rbd_image_t image, char *prefix,
2802                                          size_t prefix_len)
2803 {
2804   librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
2805   if (ictx->object_prefix.size() >= prefix_len) {
2806     return -ERANGE;
2807   }
2808
2809   strncpy(prefix, ictx->object_prefix.c_str(), prefix_len - 1);
2810   prefix[prefix_len - 1] = '\0';
2811   return 0;
2812 }
2813
2814 extern "C" int64_t rbd_get_data_pool_id(rbd_image_t image)
2815 {
2816   librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx *>(image);
2817   return ictx->data_ctx.get_id();
2818 }
2819
2820 extern "C" int rbd_get_parent_info(rbd_image_t image,
2821                                    char *parent_pool_name, size_t ppool_namelen,
2822                                    char *parent_name, size_t pnamelen,
2823                                    char *parent_snap_name, size_t psnap_namelen)
2824 {
2825   return rbd_get_parent_info2(image, parent_pool_name, ppool_namelen,
2826                               parent_name, pnamelen, nullptr, 0,
2827                               parent_snap_name, psnap_namelen);
2828 }
2829
2830 extern "C" int rbd_get_parent_info2(rbd_image_t image,
2831                                     char *parent_pool_name,
2832                                     size_t ppool_namelen,
2833                                     char *parent_name, size_t pnamelen,
2834                                     char *parent_id, size_t pidlen,
2835                                     char *parent_snap_name,
2836                                     size_t psnap_namelen)
2837 {
2838   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2839   tracepoint(librbd, get_parent_info_enter, ictx, ictx->name.c_str(),
2840              ictx->snap_name.c_str(), ictx->read_only);
2841   string p_pool_name, p_name, p_id, p_snap_name;
2842
2843   int r = librbd::get_parent_info(ictx, &p_pool_name, &p_name, &p_id,
2844                                   &p_snap_name);
2845   if (r < 0) {
2846     tracepoint(librbd, get_parent_info_exit, r, NULL, NULL, NULL, NULL);
2847     return r;
2848   }
2849
2850   if (parent_pool_name) {
2851     if (p_pool_name.length() + 1 > ppool_namelen) {
2852       tracepoint(librbd, get_parent_info_exit, -ERANGE, NULL, NULL, NULL, NULL);
2853       return -ERANGE;
2854     }
2855
2856     strcpy(parent_pool_name, p_pool_name.c_str());
2857   }
2858   if (parent_name) {
2859     if (p_name.length() + 1 > pnamelen) {
2860       tracepoint(librbd, get_parent_info_exit, -ERANGE, NULL, NULL, NULL, NULL);
2861       return -ERANGE;
2862     }
2863
2864     strcpy(parent_name, p_name.c_str());
2865   }
2866   if (parent_id) {
2867     if (p_id.length() + 1 > pidlen) {
2868       tracepoint(librbd, get_parent_info_exit, -ERANGE, NULL, NULL, NULL, NULL);
2869       return -ERANGE;
2870     }
2871
2872     strcpy(parent_id, p_id.c_str());
2873   }
2874   if (parent_snap_name) {
2875     if (p_snap_name.length() + 1 > psnap_namelen) {
2876       tracepoint(librbd, get_parent_info_exit, -ERANGE, NULL, NULL, NULL, NULL);
2877       return -ERANGE;
2878     }
2879
2880     strcpy(parent_snap_name, p_snap_name.c_str());
2881   }
2882
2883   tracepoint(librbd, get_parent_info_exit, 0, parent_pool_name, parent_name,
2884              parent_id, parent_snap_name);
2885   return 0;
2886 }
2887
2888 extern "C" int rbd_get_flags(rbd_image_t image, uint64_t *flags)
2889 {
2890   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2891   tracepoint(librbd, get_flags_enter, ictx);
2892   int r = librbd::get_flags(ictx, flags);
2893   tracepoint(librbd, get_flags_exit, ictx, r, *flags);
2894   return r;
2895 }
2896
2897 extern "C" int rbd_set_image_notification(rbd_image_t image, int fd, int type)
2898 {
2899   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2900   tracepoint(librbd, set_image_notification_enter, ictx, fd, type);
2901   int r = librbd::set_image_notification(ictx, fd, type);
2902   tracepoint(librbd, set_image_notification_exit, ictx, r);
2903   return r;
2904 }
2905
2906 extern "C" int rbd_is_exclusive_lock_owner(rbd_image_t image, int *is_owner)
2907 {
2908   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2909   tracepoint(librbd, is_exclusive_lock_owner_enter, ictx);
2910   bool owner;
2911   int r = librbd::is_exclusive_lock_owner(ictx, &owner);
2912   *is_owner = owner ? 1 : 0;
2913   tracepoint(librbd, is_exclusive_lock_owner_exit, ictx, r, *is_owner);
2914   return r;
2915 }
2916
2917 extern "C" int rbd_lock_acquire(rbd_image_t image, rbd_lock_mode_t lock_mode)
2918 {
2919   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2920   tracepoint(librbd, lock_acquire_enter, ictx, lock_mode);
2921   int r = librbd::lock_acquire(ictx, lock_mode);
2922   tracepoint(librbd, lock_acquire_exit, ictx, r);
2923   return r;
2924 }
2925
2926 extern "C" int rbd_lock_release(rbd_image_t image)
2927 {
2928   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2929   tracepoint(librbd, lock_release_enter, ictx);
2930   int r = librbd::lock_release(ictx);
2931   tracepoint(librbd, lock_release_exit, ictx, r);
2932   return r;
2933 }
2934
2935 extern "C" int rbd_lock_get_owners(rbd_image_t image,
2936                                    rbd_lock_mode_t *lock_mode,
2937                                    char **lock_owners,
2938                                    size_t *max_lock_owners)
2939 {
2940   librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx*>(image);
2941   tracepoint(librbd, lock_get_owners_enter, ictx);
2942   std::list<std::string> lock_owner_list;
2943   int r = librbd::lock_get_owners(ictx, lock_mode, &lock_owner_list);
2944   if (r >= 0) {
2945     if (*max_lock_owners >= lock_owner_list.size()) {
2946       *max_lock_owners = 0;
2947       for (auto &lock_owner : lock_owner_list) {
2948         lock_owners[(*max_lock_owners)++] = strdup(lock_owner.c_str());
2949       }
2950     } else {
2951       *max_lock_owners = lock_owner_list.size();
2952       r = -ERANGE;
2953     }
2954   }
2955   tracepoint(librbd, lock_get_owners_exit, ictx, r);
2956   return r;
2957 }
2958
2959 extern "C" void rbd_lock_get_owners_cleanup(char **lock_owners,
2960                                             size_t lock_owner_count)
2961 {
2962   for (size_t i = 0; i < lock_owner_count; ++i) {
2963     free(lock_owners[i]);
2964   }
2965 }
2966
2967 extern "C" int rbd_lock_break(rbd_image_t image, rbd_lock_mode_t lock_mode,
2968                               const char *lock_owner)
2969 {
2970   librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx*>(image);
2971   tracepoint(librbd, lock_break_enter, ictx, lock_mode, lock_owner);
2972   int r = librbd::lock_break(ictx, lock_mode, lock_owner);
2973   tracepoint(librbd, lock_break_exit, ictx, r);
2974   return r;
2975 }
2976
2977 extern "C" int rbd_rebuild_object_map(rbd_image_t image,
2978                                       librbd_progress_fn_t cb, void *cbdata)
2979 {
2980   librbd::ImageCtx *ictx = reinterpret_cast<librbd::ImageCtx*>(image);
2981   librbd::CProgressContext prog_ctx(cb, cbdata);
2982   return ictx->operations->rebuild_object_map(prog_ctx);
2983 }
2984
2985 /* snapshots */
2986 extern "C" int rbd_snap_create(rbd_image_t image, const char *snap_name)
2987 {
2988   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2989   tracepoint(librbd, snap_create_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
2990   int r = ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
2991                                         snap_name);
2992   tracepoint(librbd, snap_create_exit, r);
2993   return r;
2994 }
2995
2996 extern "C" int rbd_snap_rename(rbd_image_t image, const char *srcname, const char *dstname)
2997 {
2998   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
2999   tracepoint(librbd, snap_rename_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, srcname, dstname);
3000   int r = ictx->operations->snap_rename(srcname, dstname);
3001   tracepoint(librbd, snap_rename_exit, r);
3002   return r;
3003 }
3004
3005 extern "C" int rbd_snap_remove(rbd_image_t image, const char *snap_name)
3006 {
3007   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3008   tracepoint(librbd, snap_remove_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
3009   librbd::NoOpProgressContext prog_ctx;
3010   int r = librbd::snap_remove(ictx, snap_name, 0, prog_ctx);
3011   tracepoint(librbd, snap_remove_exit, r);
3012   return r;
3013 }
3014
3015 extern "C" int rbd_snap_remove2(rbd_image_t image, const char *snap_name, uint32_t flags,
3016                                 librbd_progress_fn_t cb, void *cbdata)
3017 {
3018   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3019   tracepoint(librbd, snap_remove2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name, flags);
3020   librbd::CProgressContext prog_ctx(cb, cbdata);
3021   int r = librbd::snap_remove(ictx, snap_name, flags, prog_ctx);
3022   tracepoint(librbd, snap_remove_exit, r);
3023   return r;
3024 }
3025
3026 extern "C" int rbd_snap_rollback(rbd_image_t image, const char *snap_name)
3027 {
3028   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3029   tracepoint(librbd, snap_rollback_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
3030   librbd::NoOpProgressContext prog_ctx;
3031   int r = ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(), snap_name, prog_ctx);
3032   tracepoint(librbd, snap_rollback_exit, r);
3033   return r;
3034 }
3035
3036 extern "C" int rbd_snap_rollback_with_progress(rbd_image_t image,
3037                                                const char *snap_name,
3038                                                librbd_progress_fn_t cb,
3039                                                void *cbdata)
3040 {
3041   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3042   tracepoint(librbd, snap_rollback_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
3043   librbd::CProgressContext prog_ctx(cb, cbdata);
3044   int r = ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(), snap_name, prog_ctx);
3045   tracepoint(librbd, snap_rollback_exit, r);
3046   return r;
3047 }
3048
3049 extern "C" int rbd_snap_list(rbd_image_t image, rbd_snap_info_t *snaps,
3050                              int *max_snaps)
3051 {
3052   vector<librbd::snap_info_t> cpp_snaps;
3053   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3054   tracepoint(librbd, snap_list_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snaps);
3055
3056   if (!max_snaps) {
3057     tracepoint(librbd, snap_list_exit, -EINVAL, 0);
3058     return -EINVAL;
3059   }
3060
3061   int r = librbd::snap_list(ictx, cpp_snaps);
3062   if (r == -ENOENT) {
3063     tracepoint(librbd, snap_list_exit, 0, *max_snaps);
3064     return 0;
3065   }
3066   if (r < 0) {
3067     tracepoint(librbd, snap_list_exit, r, *max_snaps);
3068     return r;
3069   }
3070   if (*max_snaps < (int)cpp_snaps.size() + 1) {
3071     *max_snaps = (int)cpp_snaps.size() + 1;
3072     tracepoint(librbd, snap_list_exit, -ERANGE, *max_snaps);
3073     return -ERANGE;
3074   }
3075
3076   int i;
3077
3078   for (i = 0; i < (int)cpp_snaps.size(); i++) {
3079     snaps[i].id = cpp_snaps[i].id;
3080     snaps[i].size = cpp_snaps[i].size;
3081     snaps[i].name = strdup(cpp_snaps[i].name.c_str());
3082     if (!snaps[i].name) {
3083       for (int j = 0; j < i; j++)
3084         free((void *)snaps[j].name);
3085       tracepoint(librbd, snap_list_exit, -ENOMEM, *max_snaps);
3086       return -ENOMEM;
3087     }
3088     tracepoint(librbd, snap_list_entry, snaps[i].id, snaps[i].size, snaps[i].name);
3089   }
3090   snaps[i].id = 0;
3091   snaps[i].size = 0;
3092   snaps[i].name = NULL;
3093
3094   r = (int)cpp_snaps.size();
3095   tracepoint(librbd, snap_list_exit, r, *max_snaps);
3096   return r;
3097 }
3098
3099 extern "C" void rbd_snap_list_end(rbd_snap_info_t *snaps)
3100 {
3101   tracepoint(librbd, snap_list_end_enter, snaps);
3102   while (snaps->name) {
3103     free((void *)snaps->name);
3104     snaps++;
3105   }
3106   tracepoint(librbd, snap_list_end_exit);
3107 }
3108
3109 extern "C" int rbd_snap_protect(rbd_image_t image, const char *snap_name)
3110 {
3111   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3112   tracepoint(librbd, snap_protect_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
3113   int r = ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(), snap_name);
3114   tracepoint(librbd, snap_protect_exit, r);
3115   return r;
3116 }
3117
3118 extern "C" int rbd_snap_unprotect(rbd_image_t image, const char *snap_name)
3119 {
3120   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3121   tracepoint(librbd, snap_unprotect_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
3122   int r = ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(), snap_name);
3123   tracepoint(librbd, snap_unprotect_exit, r);
3124   return r;
3125 }
3126
3127 extern "C" int rbd_snap_is_protected(rbd_image_t image, const char *snap_name,
3128                                      int *is_protected)
3129 {
3130   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3131   tracepoint(librbd, snap_is_protected_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
3132   bool protected_snap;
3133   int r = librbd::snap_is_protected(ictx, snap_name, &protected_snap);
3134   if (r < 0) {
3135     tracepoint(librbd, snap_is_protected_exit, r, *is_protected ? 1 : 0);
3136     return r;
3137   }
3138   *is_protected = protected_snap ? 1 : 0;
3139   tracepoint(librbd, snap_is_protected_exit, 0, *is_protected ? 1 : 0);
3140   return 0;
3141 }
3142
3143 extern "C" int rbd_snap_get_limit(rbd_image_t image, uint64_t *limit)
3144 {
3145   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3146   tracepoint(librbd, snap_get_limit_enter, ictx, ictx->name.c_str());
3147   int r = librbd::snap_get_limit(ictx, limit);
3148   tracepoint(librbd, snap_get_limit_exit, r, *limit);
3149   return r;
3150 }
3151
3152 extern "C" int rbd_snap_get_timestamp(rbd_image_t image, uint64_t snap_id, struct timespec *timestamp)
3153 {
3154   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3155   tracepoint(librbd, snap_get_timestamp_enter, ictx, ictx->name.c_str());
3156   int r = librbd::snap_get_timestamp(ictx, snap_id, timestamp);
3157   tracepoint(librbd, snap_get_timestamp_exit, r);
3158   return r;
3159 }
3160
3161 extern "C" int rbd_snap_set_limit(rbd_image_t image, uint64_t limit)
3162 {
3163   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3164   tracepoint(librbd, snap_set_limit_enter, ictx, ictx->name.c_str(), limit);
3165   int r = librbd::snap_set_limit(ictx, limit);
3166   tracepoint(librbd, snap_set_limit_exit, r);
3167   return r;
3168 }
3169
3170 extern "C" int rbd_snap_set(rbd_image_t image, const char *snap_name)
3171 {
3172   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3173   tracepoint(librbd, snap_set_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, snap_name);
3174   int r = librbd::snap_set(ictx, cls::rbd::UserSnapshotNamespace(), snap_name);
3175   tracepoint(librbd, snap_set_exit, r);
3176   return r;
3177 }
3178
3179 extern "C" ssize_t rbd_list_children(rbd_image_t image, char *pools,
3180                                      size_t *pools_len, char *images,
3181                                      size_t *images_len)
3182 {
3183   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3184   tracepoint(librbd, list_children_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
3185   set<pair<string, string> > image_set;
3186
3187   int r = librbd::list_children(ictx, image_set);
3188   if (r < 0) {
3189     tracepoint(librbd, list_children_exit, r);
3190     return r;
3191   }
3192
3193   size_t pools_total = 0;
3194   size_t images_total = 0;
3195   for (set<pair<string, string> >::const_iterator it = image_set.begin();
3196        it != image_set.end(); ++it) {
3197     pools_total += it->first.length() + 1;
3198     images_total += it->second.length() + 1;
3199   }
3200
3201   bool too_short = false;
3202   if (pools_total > *pools_len)
3203     too_short = true;
3204   if (images_total > *images_len)
3205     too_short = true;
3206   *pools_len = pools_total;
3207   *images_len = images_total;
3208   if (too_short) {
3209     tracepoint(librbd, list_children_exit, -ERANGE);
3210     return -ERANGE;
3211   }
3212
3213   char *pools_p = pools;
3214   char *images_p = images;
3215   for (set<pair<string, string> >::const_iterator it = image_set.begin();
3216        it != image_set.end(); ++it) {
3217     const char* pool = it->first.c_str();
3218     strcpy(pools_p, pool);
3219     pools_p += it->first.length() + 1;
3220     const char* image = it->second.c_str();
3221     strcpy(images_p, image);
3222     images_p += it->second.length() + 1;
3223     tracepoint(librbd, list_children_entry, pool, image);
3224   }
3225
3226   ssize_t ret = image_set.size();
3227   tracepoint(librbd, list_children_exit, ret);
3228   return ret;
3229 }
3230
3231 extern "C" ssize_t rbd_list_lockers(rbd_image_t image, int *exclusive,
3232                                     char *tag, size_t *tag_len,
3233                                     char *clients, size_t *clients_len,
3234                                     char *cookies, size_t *cookies_len,
3235                                     char *addrs, size_t *addrs_len)
3236 {
3237   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3238   tracepoint(librbd, list_lockers_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
3239   std::list<librbd::locker_t> lockers;
3240   bool exclusive_bool;
3241   string tag_str;
3242
3243   int r = list_lockers(ictx, &lockers, &exclusive_bool, &tag_str);
3244   if (r < 0) {
3245     tracepoint(librbd, list_lockers_exit, r);
3246     return r;
3247   }
3248
3249   ldout(ictx->cct, 20) << "list_lockers r = " << r << " lockers.size() = " << lockers.size() << dendl;
3250
3251   *exclusive = (int)exclusive_bool;
3252   size_t clients_total = 0;
3253   size_t cookies_total = 0;
3254   size_t addrs_total = 0;
3255   for (list<librbd::locker_t>::const_iterator it = lockers.begin();
3256        it != lockers.end(); ++it) {
3257     clients_total += it->client.length() + 1;
3258     cookies_total += it->cookie.length() + 1;
3259     addrs_total += it->address.length() + 1;
3260   }
3261
3262   bool too_short = ((clients_total > *clients_len) ||
3263                     (cookies_total > *cookies_len) ||
3264                     (addrs_total > *addrs_len) ||
3265                     (tag_str.length() + 1 > *tag_len));
3266   *clients_len = clients_total;
3267   *cookies_len = cookies_total;
3268   *addrs_len = addrs_total;
3269   *tag_len = tag_str.length() + 1;
3270   if (too_short) {
3271     tracepoint(librbd, list_lockers_exit, -ERANGE);
3272     return -ERANGE;
3273   }
3274
3275   strcpy(tag, tag_str.c_str());
3276   char *clients_p = clients;
3277   char *cookies_p = cookies;
3278   char *addrs_p = addrs;
3279   for (list<librbd::locker_t>::const_iterator it = lockers.begin();
3280        it != lockers.end(); ++it) {
3281     const char* client = it->client.c_str();
3282     strcpy(clients_p, client);
3283     clients_p += it->client.length() + 1;
3284     const char* cookie = it->cookie.c_str();
3285     strcpy(cookies_p, cookie);
3286     cookies_p += it->cookie.length() + 1;
3287     const char* address = it->address.c_str();
3288     strcpy(addrs_p, address);
3289     addrs_p += it->address.length() + 1;
3290     tracepoint(librbd, list_lockers_entry, client, cookie, address);
3291   }
3292
3293   ssize_t ret = lockers.size();
3294   tracepoint(librbd, list_lockers_exit, ret);
3295   return ret;
3296 }
3297
3298 extern "C" int rbd_lock_exclusive(rbd_image_t image, const char *cookie)
3299 {
3300   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3301   tracepoint(librbd, lock_exclusive_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie);
3302   int r = librbd::lock(ictx, true, cookie ? cookie : "", "");
3303   tracepoint(librbd, lock_exclusive_exit, r);
3304   return r;
3305 }
3306
3307 extern "C" int rbd_lock_shared(rbd_image_t image, const char *cookie,
3308                                const char *tag)
3309 {
3310   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3311   tracepoint(librbd, lock_shared_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie, tag);
3312   int r = librbd::lock(ictx, false, cookie ? cookie : "", tag ? tag : "");
3313   tracepoint(librbd, lock_shared_exit, r);
3314   return r;
3315 }
3316
3317 extern "C" int rbd_unlock(rbd_image_t image, const char *cookie)
3318 {
3319   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3320   tracepoint(librbd, unlock_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, cookie);
3321   int r = librbd::unlock(ictx, cookie ? cookie : "");
3322   tracepoint(librbd, unlock_exit, r);
3323   return r;
3324 }
3325
3326 extern "C" int rbd_break_lock(rbd_image_t image, const char *client,
3327                               const char *cookie)
3328 {
3329   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3330   tracepoint(librbd, break_lock_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, client, cookie);
3331   int r = librbd::break_lock(ictx, client, cookie ? cookie : "");
3332   tracepoint(librbd, break_lock_exit, r);
3333   return r;
3334 }
3335
3336 /* I/O */
3337 extern "C" ssize_t rbd_read(rbd_image_t image, uint64_t ofs, size_t len,
3338                             char *buf)
3339 {
3340   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3341   tracepoint(librbd, read_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
3342   int r = ictx->io_work_queue->read(ofs, len, librbd::io::ReadResult{buf, len},
3343                                     0);
3344   tracepoint(librbd, read_exit, r);
3345   return r;
3346 }
3347
3348 extern "C" ssize_t rbd_read2(rbd_image_t image, uint64_t ofs, size_t len,
3349                               char *buf, int op_flags)
3350 {
3351   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3352   tracepoint(librbd, read2_enter, ictx, ictx->name.c_str(),
3353               ictx->snap_name.c_str(), ictx->read_only, ofs, len, op_flags);
3354   int r = ictx->io_work_queue->read(ofs, len, librbd::io::ReadResult{buf, len},
3355                                     op_flags);
3356   tracepoint(librbd, read_exit, r);
3357   return r;
3358 }
3359
3360
3361 extern "C" int64_t rbd_read_iterate(rbd_image_t image, uint64_t ofs, size_t len,
3362                                     int (*cb)(uint64_t, size_t, const char *, void *),
3363                                     void *arg)
3364 {
3365   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3366   tracepoint(librbd, read_iterate_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
3367   int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg);
3368   tracepoint(librbd, read_iterate_exit, r);
3369   return r;
3370 }
3371
3372 extern "C" int rbd_read_iterate2(rbd_image_t image, uint64_t ofs, uint64_t len,
3373                                  int (*cb)(uint64_t, size_t, const char *, void *),
3374                                  void *arg)
3375 {
3376   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3377   tracepoint(librbd, read_iterate2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
3378   int64_t r = librbd::read_iterate(ictx, ofs, len, cb, arg);
3379   if (r > 0)
3380     r = 0;
3381   tracepoint(librbd, read_iterate2_exit, r);
3382   return (int)r;
3383 }
3384
3385 extern "C" int rbd_diff_iterate(rbd_image_t image,
3386                                 const char *fromsnapname,
3387                                 uint64_t ofs, uint64_t len,
3388                                 int (*cb)(uint64_t, size_t, int, void *),
3389                                 void *arg)
3390 {
3391   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3392   tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(),
3393              ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len,
3394              true, false);
3395   int r = librbd::api::DiffIterate<>::diff_iterate(ictx,
3396                                                    cls::rbd::UserSnapshotNamespace(),
3397                                                    fromsnapname, ofs, len,
3398                                                    true, false, cb, arg);
3399   tracepoint(librbd, diff_iterate_exit, r);
3400   return r;
3401 }
3402
3403 extern "C" int rbd_diff_iterate2(rbd_image_t image, const char *fromsnapname,
3404                                 uint64_t ofs, uint64_t len,
3405                                 uint8_t include_parent, uint8_t whole_object,
3406                                 int (*cb)(uint64_t, size_t, int, void *),
3407                                 void *arg)
3408 {
3409   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3410   tracepoint(librbd, diff_iterate_enter, ictx, ictx->name.c_str(),
3411             ictx->snap_name.c_str(), ictx->read_only, fromsnapname, ofs, len,
3412             include_parent != 0, whole_object != 0);
3413   int r = librbd::api::DiffIterate<>::diff_iterate(ictx,
3414                                                    cls::rbd::UserSnapshotNamespace(),
3415                                                    fromsnapname, ofs, len,
3416                                                    include_parent, whole_object,
3417                                                    cb, arg);
3418   tracepoint(librbd, diff_iterate_exit, r);
3419   return r;
3420 }
3421
3422 extern "C" ssize_t rbd_write(rbd_image_t image, uint64_t ofs, size_t len,
3423                              const char *buf)
3424 {
3425   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3426   tracepoint(librbd, write_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len, buf);
3427
3428   bufferlist bl;
3429   bl.push_back(create_write_raw(ictx, buf, len));
3430   int r = ictx->io_work_queue->write(ofs, len, std::move(bl), 0);
3431   tracepoint(librbd, write_exit, r);
3432   return r;
3433 }
3434
3435 extern "C" ssize_t rbd_write2(rbd_image_t image, uint64_t ofs, size_t len,
3436                               const char *buf, int op_flags)
3437 {
3438   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3439   tracepoint(librbd, write2_enter, ictx, ictx->name.c_str(),
3440               ictx->snap_name.c_str(), ictx->read_only, ofs, len, buf, op_flags);
3441
3442   bufferlist bl;
3443   bl.push_back(create_write_raw(ictx, buf, len));
3444   int r = ictx->io_work_queue->write(ofs, len, std::move(bl), op_flags);
3445   tracepoint(librbd, write_exit, r);
3446   return r;
3447 }
3448
3449
3450 extern "C" int rbd_discard(rbd_image_t image, uint64_t ofs, uint64_t len)
3451 {
3452   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3453   tracepoint(librbd, discard_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, ofs, len);
3454   int r = ictx->io_work_queue->discard(ofs, len, ictx->skip_partial_discard);
3455   tracepoint(librbd, discard_exit, r);
3456   return r;
3457 }
3458
3459 extern "C" ssize_t rbd_writesame(rbd_image_t image, uint64_t ofs, size_t len,
3460                                  const char *buf, size_t data_len, int op_flags)
3461 {
3462   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3463   tracepoint(librbd, writesame_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
3464              ictx->read_only, ofs, len, data_len <= 0 ? NULL : buf, data_len, op_flags);
3465
3466   if (data_len <= 0 || len % data_len) {
3467     tracepoint(librbd, writesame_exit, -EINVAL);
3468     return -EINVAL;
3469   }
3470
3471   if (mem_is_zero(buf, data_len)) {
3472     int r = ictx->io_work_queue->discard(ofs, len, false);
3473     tracepoint(librbd, writesame_exit, r);
3474     return r;
3475   }
3476
3477   bufferlist bl;
3478   bl.push_back(create_write_raw(ictx, buf, data_len));
3479   int r = ictx->io_work_queue->writesame(ofs, len, std::move(bl), op_flags);
3480   tracepoint(librbd, writesame_exit, r);
3481   return r;
3482 }
3483
3484 extern "C" ssize_t rbd_compare_and_write(rbd_image_t image,
3485                                          uint64_t ofs, size_t len,
3486                                          const char *cmp_buf,
3487                                          const char *buf,
3488                                          uint64_t *mismatch_off,
3489                                          int op_flags)
3490 {
3491   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3492   tracepoint(librbd, compare_and_write_enter, ictx, ictx->name.c_str(),
3493              ictx->snap_name.c_str(), ictx->read_only, ofs,
3494              len, cmp_buf, buf, op_flags);
3495
3496   bufferlist cmp_bl;
3497   cmp_bl.push_back(create_write_raw(ictx, cmp_buf, len));
3498   bufferlist bl;
3499   bl.push_back(create_write_raw(ictx, buf, len));
3500
3501   int r = ictx->io_work_queue->compare_and_write(ofs, len, std::move(cmp_bl),
3502                                                  std::move(bl), mismatch_off,
3503                                                  op_flags);
3504   tracepoint(librbd, compare_and_write_exit, r);
3505   return r;
3506 }
3507
3508 extern "C" int rbd_aio_create_completion(void *cb_arg,
3509                                          rbd_callback_t complete_cb,
3510                                          rbd_completion_t *c)
3511 {
3512   librbd::RBD::AioCompletion *rbd_comp =
3513     new librbd::RBD::AioCompletion(cb_arg, complete_cb);
3514   *c = (rbd_completion_t) rbd_comp;
3515   return 0;
3516 }
3517
3518 extern "C" int rbd_aio_write(rbd_image_t image, uint64_t off, size_t len,
3519                              const char *buf, rbd_completion_t c)
3520 {
3521   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3522   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3523   tracepoint(librbd, aio_write_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, buf, comp->pc);
3524
3525   bufferlist bl;
3526   bl.push_back(create_write_raw(ictx, buf, len));
3527   ictx->io_work_queue->aio_write(get_aio_completion(comp), off, len,
3528                                  std::move(bl), 0);
3529   tracepoint(librbd, aio_write_exit, 0);
3530   return 0;
3531 }
3532
3533 extern "C" int rbd_aio_write2(rbd_image_t image, uint64_t off, size_t len,
3534                               const char *buf, rbd_completion_t c, int op_flags)
3535 {
3536   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3537   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3538   tracepoint(librbd, aio_write2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
3539               ictx->read_only, off, len, buf, comp->pc, op_flags);
3540
3541   bufferlist bl;
3542   bl.push_back(create_write_raw(ictx, buf, len));
3543   ictx->io_work_queue->aio_write(get_aio_completion(comp), off, len,
3544                                  std::move(bl), op_flags);
3545   tracepoint(librbd, aio_write_exit, 0);
3546   return 0;
3547 }
3548
3549 extern "C" int rbd_aio_writev(rbd_image_t image, const struct iovec *iov,
3550                               int iovcnt, uint64_t off, rbd_completion_t c)
3551 {
3552   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3553   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3554
3555   // convert the scatter list into a bufferlist
3556   ssize_t len = 0;
3557   bufferlist bl;
3558   for (int i = 0; i < iovcnt; ++i) {
3559     const struct iovec &io = iov[i];
3560     len += io.iov_len;
3561     if (len < 0) {
3562       break;
3563     }
3564
3565     bl.push_back(create_write_raw(ictx, static_cast<char*>(io.iov_base),
3566                                   io.iov_len));
3567   }
3568
3569   int r = 0;
3570   if (iovcnt <= 0 || len < 0) {
3571     r = -EINVAL;
3572   }
3573
3574   tracepoint(librbd, aio_write_enter, ictx, ictx->name.c_str(),
3575              ictx->snap_name.c_str(), ictx->read_only, off, len, NULL,
3576              comp->pc);
3577   if (r == 0) {
3578     ictx->io_work_queue->aio_write(get_aio_completion(comp), off, len,
3579                                    std::move(bl), 0);
3580   }
3581   tracepoint(librbd, aio_write_exit, r);
3582   return r;
3583 }
3584
3585 extern "C" int rbd_aio_discard(rbd_image_t image, uint64_t off, uint64_t len,
3586                                rbd_completion_t c)
3587 {
3588   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3589   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3590   tracepoint(librbd, aio_discard_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, comp->pc);
3591   ictx->io_work_queue->aio_discard(get_aio_completion(comp), off, len, ictx->skip_partial_discard);
3592   tracepoint(librbd, aio_discard_exit, 0);
3593   return 0;
3594 }
3595
3596 extern "C" int rbd_aio_read(rbd_image_t image, uint64_t off, size_t len,
3597                             char *buf, rbd_completion_t c)
3598 {
3599   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3600   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3601   tracepoint(librbd, aio_read_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, off, len, buf, comp->pc);
3602   ictx->io_work_queue->aio_read(get_aio_completion(comp), off, len,
3603                                 librbd::io::ReadResult{buf, len}, 0);
3604   tracepoint(librbd, aio_read_exit, 0);
3605   return 0;
3606 }
3607
3608 extern "C" int rbd_aio_read2(rbd_image_t image, uint64_t off, size_t len,
3609                               char *buf, rbd_completion_t c, int op_flags)
3610 {
3611   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3612   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3613   tracepoint(librbd, aio_read2_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
3614               ictx->read_only, off, len, buf, comp->pc, op_flags);
3615   ictx->io_work_queue->aio_read(get_aio_completion(comp), off, len,
3616                                 librbd::io::ReadResult{buf, len},op_flags);
3617   tracepoint(librbd, aio_read_exit, 0);
3618   return 0;
3619 }
3620
3621 extern "C" int rbd_aio_readv(rbd_image_t image, const struct iovec *iov,
3622                              int iovcnt, uint64_t off, rbd_completion_t c)
3623 {
3624   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3625   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3626
3627   ssize_t len = 0;
3628   for (int i = 0; i < iovcnt; ++i) {
3629     len += iov[i].iov_len;
3630     if (len < 0) {
3631       break;
3632     }
3633   }
3634
3635   int r = 0;
3636   if (iovcnt == 0 || len < 0) {
3637     r = -EINVAL;
3638   }
3639
3640   tracepoint(librbd, aio_read_enter, ictx, ictx->name.c_str(),
3641              ictx->snap_name.c_str(), ictx->read_only, off, len, NULL,
3642              comp->pc);
3643   if (r == 0) {
3644     librbd::io::ReadResult read_result;
3645     if (iovcnt == 1) {
3646       read_result = librbd::io::ReadResult(
3647         static_cast<char *>(iov[0].iov_base), iov[0].iov_len);
3648     } else {
3649       read_result = librbd::io::ReadResult(iov, iovcnt);
3650     }
3651     ictx->io_work_queue->aio_read(get_aio_completion(comp), off, len,
3652                                   std::move(read_result), 0);
3653   }
3654   tracepoint(librbd, aio_read_exit, r);
3655   return r;
3656 }
3657
3658 extern "C" int rbd_flush(rbd_image_t image)
3659 {
3660   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3661   tracepoint(librbd, flush_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
3662   int r = librbd::flush(ictx);
3663   tracepoint(librbd, flush_exit, r);
3664   return r;
3665 }
3666
3667 extern "C" int rbd_aio_flush(rbd_image_t image, rbd_completion_t c)
3668 {
3669   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3670   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3671   tracepoint(librbd, aio_flush_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only, comp->pc);
3672   ictx->io_work_queue->aio_flush(get_aio_completion(comp));
3673   tracepoint(librbd, aio_flush_exit, 0);
3674   return 0;
3675 }
3676
3677 extern "C" int rbd_aio_writesame(rbd_image_t image, uint64_t off, size_t len,
3678                                  const char *buf, size_t data_len, rbd_completion_t c,
3679                                  int op_flags)
3680 {
3681   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3682   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3683   tracepoint(librbd, aio_writesame_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
3684              ictx->read_only, off, len, data_len <= 0 ? NULL : buf, data_len, comp->pc,
3685              op_flags);
3686
3687   if (data_len <= 0 || len % data_len) {
3688     tracepoint(librbd, aio_writesame_exit, -EINVAL);
3689     return -EINVAL;
3690   }
3691
3692   if (mem_is_zero(buf, data_len)) {
3693     ictx->io_work_queue->aio_discard(get_aio_completion(comp), off, len, false);
3694     tracepoint(librbd, aio_writesame_exit, 0);
3695     return 0;
3696   }
3697
3698   bufferlist bl;
3699   bl.push_back(create_write_raw(ictx, buf, data_len));
3700   ictx->io_work_queue->aio_writesame(get_aio_completion(comp), off, len,
3701                                      std::move(bl), op_flags);
3702   tracepoint(librbd, aio_writesame_exit, 0);
3703   return 0;
3704 }
3705
3706 extern "C" ssize_t rbd_aio_compare_and_write(rbd_image_t image, uint64_t off,
3707                                              size_t len, const char *cmp_buf,
3708                                              const char *buf, rbd_completion_t c,
3709                                              uint64_t *mismatch_off,
3710                                              int op_flags)
3711 {
3712   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3713   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3714   tracepoint(librbd, aio_compare_and_write_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(),
3715               ictx->read_only, off, len, cmp_buf, buf, comp->pc, op_flags);
3716
3717   bufferlist cmp_bl;
3718   cmp_bl.push_back(create_write_raw(ictx, cmp_buf, len));
3719   bufferlist bl;
3720   bl.push_back(create_write_raw(ictx, buf, len));
3721   ictx->io_work_queue->aio_compare_and_write(get_aio_completion(comp), off, len,
3722                                              std::move(cmp_bl), std::move(bl),
3723                                              mismatch_off, op_flags, false);
3724
3725   tracepoint(librbd, aio_compare_and_write_exit, 0);
3726   return 0;
3727 }
3728
3729 extern "C" int rbd_invalidate_cache(rbd_image_t image)
3730 {
3731   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3732   tracepoint(librbd, invalidate_cache_enter, ictx, ictx->name.c_str(), ictx->snap_name.c_str(), ictx->read_only);
3733   int r = librbd::invalidate_cache(ictx);
3734   tracepoint(librbd, invalidate_cache_exit, r);
3735   return r;
3736 }
3737
3738 extern "C" int rbd_poll_io_events(rbd_image_t image, rbd_completion_t *comps, int numcomp)
3739 {
3740   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3741   librbd::io::AioCompletion *cs[numcomp];
3742   tracepoint(librbd, poll_io_events_enter, ictx, numcomp);
3743   int r = librbd::poll_io_events(ictx, cs, numcomp);
3744   tracepoint(librbd, poll_io_events_exit, r);
3745   if (r > 0) {
3746     for (int i = 0; i < r; ++i)
3747       comps[i] = cs[i]->rbd_comp;
3748   }
3749   return r;
3750 }
3751
3752 extern "C" int rbd_metadata_get(rbd_image_t image, const char *key, char *value, size_t *vallen)
3753 {
3754   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3755   string val_s;
3756   tracepoint(librbd, metadata_get_enter, ictx, key);
3757   int r = librbd::metadata_get(ictx, key, &val_s);
3758   if (r < 0) {
3759     tracepoint(librbd, metadata_get_exit, r, key, NULL);
3760     return r;
3761   }
3762   if (*vallen < val_s.size() + 1) {
3763     r = -ERANGE;
3764     *vallen = val_s.size() + 1;
3765     tracepoint(librbd, metadata_get_exit, r, key, NULL);
3766   } else {
3767     strncpy(value, val_s.c_str(), val_s.size() + 1);
3768     tracepoint(librbd, metadata_get_exit, r, key, value);
3769   }
3770   return r;
3771 }
3772
3773 extern "C" int rbd_metadata_set(rbd_image_t image, const char *key, const char *value)
3774 {
3775   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3776   tracepoint(librbd, metadata_set_enter, ictx, key, value);
3777   int r = ictx->operations->metadata_set(key, value);
3778   tracepoint(librbd, metadata_set_exit, r);
3779   return r;
3780 }
3781
3782 extern "C" int rbd_metadata_remove(rbd_image_t image, const char *key)
3783 {
3784   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3785   tracepoint(librbd, metadata_remove_enter, ictx, key);
3786   int r = ictx->operations->metadata_remove(key);
3787   tracepoint(librbd, metadata_remove_exit, r);
3788   return r;
3789 }
3790
3791 extern "C" int rbd_metadata_list(rbd_image_t image, const char *start, uint64_t max,
3792                                  char *key, size_t *key_len, char *value, size_t *val_len)
3793 {
3794   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3795   tracepoint(librbd, metadata_list_enter, ictx);
3796   map<string, bufferlist> pairs;
3797   int r = librbd::metadata_list(ictx, start, max, &pairs);
3798   size_t key_total_len = 0, val_total_len = 0;
3799   bool too_short = false;
3800   for (map<string, bufferlist>::iterator it = pairs.begin();
3801        it != pairs.end(); ++it) {
3802     key_total_len += it->first.size() + 1;
3803     val_total_len += it->second.length() + 1;
3804   }
3805   if (*key_len < key_total_len || *val_len < val_total_len)
3806     too_short = true;
3807   *key_len = key_total_len;
3808   *val_len = val_total_len;
3809   if (too_short) {
3810     tracepoint(librbd, metadata_list_exit, -ERANGE);
3811     return -ERANGE;
3812   }
3813
3814   char *key_p = key, *value_p = value;
3815
3816   for (map<string, bufferlist>::iterator it = pairs.begin();
3817        it != pairs.end(); ++it) {
3818     strncpy(key_p, it->first.c_str(), it->first.size() + 1);
3819     key_p += it->first.size() + 1;
3820     strncpy(value_p, it->second.c_str(), it->second.length());
3821     value_p += it->second.length();
3822     *value_p = '\0';
3823     value_p++;
3824     tracepoint(librbd, metadata_list_entry, it->first.c_str(), it->second.c_str());
3825   }
3826   tracepoint(librbd, metadata_list_exit, r);
3827   return r;
3828 }
3829
3830 extern "C" int rbd_mirror_image_enable(rbd_image_t image)
3831 {
3832   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3833   return librbd::api::Mirror<>::image_enable(ictx, false);
3834 }
3835
3836 extern "C" int rbd_mirror_image_disable(rbd_image_t image, bool force)
3837 {
3838   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3839   return librbd::api::Mirror<>::image_disable(ictx, force);
3840 }
3841
3842 extern "C" int rbd_mirror_image_promote(rbd_image_t image, bool force)
3843 {
3844   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3845   return librbd::api::Mirror<>::image_promote(ictx, force);
3846 }
3847
3848 extern "C" int rbd_mirror_image_demote(rbd_image_t image)
3849 {
3850   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3851   return librbd::api::Mirror<>::image_demote(ictx);
3852 }
3853
3854 extern "C" int rbd_mirror_image_resync(rbd_image_t image)
3855 {
3856   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3857   return librbd::api::Mirror<>::image_resync(ictx);
3858 }
3859
3860 extern "C" int rbd_mirror_image_get_info(rbd_image_t image,
3861                                          rbd_mirror_image_info_t *mirror_image_info,
3862                                          size_t info_size)
3863 {
3864   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3865
3866   librbd::mirror_image_info_t cpp_mirror_image;
3867   int r = librbd::api::Mirror<>::image_get_info(ictx, &cpp_mirror_image,
3868                                                 sizeof(cpp_mirror_image));
3869   if (r < 0) {
3870     return r;
3871   }
3872
3873   mirror_image_info_cpp_to_c(cpp_mirror_image, mirror_image_info);
3874   return 0;
3875 }
3876
3877 extern "C" int rbd_mirror_image_get_status(rbd_image_t image,
3878                                            rbd_mirror_image_status_t *status,
3879                                            size_t status_size)
3880 {
3881   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3882
3883   librbd::mirror_image_status_t cpp_status;
3884   int r = librbd::api::Mirror<>::image_get_status(ictx, &cpp_status,
3885                                                   sizeof(cpp_status));
3886   if (r < 0) {
3887     return r;
3888   }
3889
3890   mirror_image_status_cpp_to_c(cpp_status, status);
3891   return 0;
3892 }
3893
3894 extern "C" int rbd_aio_mirror_image_promote(rbd_image_t image, bool force,
3895                                             rbd_completion_t c) {
3896   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3897   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3898   librbd::api::Mirror<>::image_promote(
3899     ictx, force, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
3900                                      get_aio_completion(comp)));
3901   return 0;
3902 }
3903
3904 extern "C" int rbd_aio_mirror_image_demote(rbd_image_t image,
3905                                            rbd_completion_t c) {
3906   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3907   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3908   librbd::api::Mirror<>::image_demote(
3909     ictx, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
3910                               get_aio_completion(comp)));
3911   return 0;
3912 }
3913
3914 extern "C" int rbd_aio_mirror_image_get_info(rbd_image_t image,
3915                                              rbd_mirror_image_info_t *info,
3916                                              size_t info_size,
3917                                              rbd_completion_t c) {
3918   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3919   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3920
3921   if (sizeof(rbd_mirror_image_info_t) > info_size) {
3922     return -ERANGE;
3923   }
3924
3925   auto ctx = new C_MirrorImageGetInfo(
3926     info, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
3927                               get_aio_completion(comp)));
3928   librbd::api::Mirror<>::image_get_info(
3929     ictx, &ctx->cpp_mirror_image_info, sizeof(ctx->cpp_mirror_image_info), ctx);
3930   return 0;
3931 }
3932
3933 extern "C" int rbd_aio_mirror_image_get_status(rbd_image_t image,
3934                                                rbd_mirror_image_status_t *status,
3935                                                size_t status_size,
3936                                                rbd_completion_t c) {
3937   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3938   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3939
3940   if (sizeof(rbd_mirror_image_status_t) > status_size) {
3941     return -ERANGE;
3942   }
3943
3944   auto ctx = new C_MirrorImageGetStatus(
3945     status, new C_AioCompletion(ictx, librbd::io::AIO_TYPE_GENERIC,
3946                                 get_aio_completion(comp)));
3947   librbd::api::Mirror<>::image_get_status(
3948     ictx, &ctx->cpp_mirror_image_status, sizeof(ctx->cpp_mirror_image_status),
3949     ctx);
3950   return 0;
3951 }
3952
3953 extern "C" int rbd_update_watch(rbd_image_t image, uint64_t *handle,
3954                                 rbd_update_callback_t watch_cb, void *arg)
3955 {
3956   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3957   C_UpdateWatchCB *wctx = new C_UpdateWatchCB(watch_cb, arg);
3958   tracepoint(librbd, update_watch_enter, ictx, wctx);
3959   int r = ictx->state->register_update_watcher(wctx, &wctx->handle);
3960   tracepoint(librbd, update_watch_exit, r, wctx->handle);
3961   *handle = reinterpret_cast<uint64_t>(wctx);
3962   return r;
3963 }
3964
3965 extern "C" int rbd_update_unwatch(rbd_image_t image, uint64_t handle)
3966 {
3967   librbd::ImageCtx *ictx = (librbd::ImageCtx *)image;
3968   C_UpdateWatchCB *wctx = reinterpret_cast<C_UpdateWatchCB *>(handle);
3969   tracepoint(librbd, update_unwatch_enter, ictx, wctx->handle);
3970   int r = ictx->state->unregister_update_watcher(wctx->handle);
3971   delete wctx;
3972   tracepoint(librbd, update_unwatch_exit, r);
3973   return r;
3974 }
3975
3976 extern "C" int rbd_aio_is_complete(rbd_completion_t c)
3977 {
3978   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3979   return comp->is_complete();
3980 }
3981
3982 extern "C" int rbd_aio_wait_for_complete(rbd_completion_t c)
3983 {
3984   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3985   return comp->wait_for_complete();
3986 }
3987
3988 extern "C" ssize_t rbd_aio_get_return_value(rbd_completion_t c)
3989 {
3990   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3991   return comp->get_return_value();
3992 }
3993
3994 extern "C" void *rbd_aio_get_arg(rbd_completion_t c)
3995 {
3996   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
3997   return comp->get_arg();
3998 }
3999
4000 extern "C" void rbd_aio_release(rbd_completion_t c)
4001 {
4002   librbd::RBD::AioCompletion *comp = (librbd::RBD::AioCompletion *)c;
4003   comp->release();
4004 }
4005