]> git.proxmox.com Git - ceph.git/blame - ceph/src/objclass/class_api.cc
update sources to v12.1.2
[ceph.git] / ceph / src / objclass / class_api.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "common/config.h"
5#include "common/debug.h"
6
7#include "objclass/objclass.h"
8#include "osd/PrimaryLogPG.h"
9#include "osd/osd_types.h"
10
11#include "osd/ClassHandler.h"
12
13#include "auth/Crypto.h"
14#include "common/armor.h"
15
16static constexpr int dout_subsys = ceph_subsys_objclass;
17
18static ClassHandler *ch;
19
20void cls_initialize(ClassHandler *h)
21{
22 ch = h;
23}
24
25void cls_finalize()
26{
27 ch = NULL;
28}
29
30
31void *cls_alloc(size_t size)
32{
33 return malloc(size);
34}
35
36void cls_free(void *p)
37{
38 free(p);
39}
40
41int cls_register(const char *name, cls_handle_t *handle)
42{
43 ClassHandler::ClassData *cls = ch->register_class(name);
44 *handle = (cls_handle_t)cls;
45 return (cls != NULL);
46}
47
48int cls_unregister(cls_handle_t handle)
49{
50 ClassHandler::ClassData *cls = (ClassHandler::ClassData *)handle;
51 ch->unregister_class(cls);
52 return 1;
53}
54
55int cls_register_method(cls_handle_t hclass, const char *method,
56 int flags,
57 cls_method_call_t class_call, cls_method_handle_t *handle)
58{
59 if (!(flags & (CLS_METHOD_RD | CLS_METHOD_WR)))
60 return -EINVAL;
61 ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass;
62 cls_method_handle_t hmethod =(cls_method_handle_t)cls->register_method(method, flags, class_call);
63 if (handle)
64 *handle = hmethod;
65 return (hmethod != NULL);
66}
67
68int cls_register_cxx_method(cls_handle_t hclass, const char *method,
69 int flags,
70 cls_method_cxx_call_t class_call, cls_method_handle_t *handle)
71{
72 ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass;
73 cls_method_handle_t hmethod = (cls_method_handle_t)cls->register_cxx_method(method, flags, class_call);
74 if (handle)
75 *handle = hmethod;
76 return (hmethod != NULL);
77}
78
79int cls_unregister_method(cls_method_handle_t handle)
80{
81 ClassHandler::ClassMethod *method = (ClassHandler::ClassMethod *)handle;
82 method->unregister();
83 return 1;
84}
85
86int cls_register_cxx_filter(cls_handle_t hclass,
87 const std::string &filter_name,
88 cls_cxx_filter_factory_t fn,
89 cls_filter_handle_t *handle)
90{
91 ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass;
92 cls_filter_handle_t hfilter = (cls_filter_handle_t)cls->register_cxx_filter(filter_name, fn);
93 if (handle) {
94 *handle = hfilter;
95 }
96 return (hfilter != NULL);
97}
98
99void cls_unregister_filter(cls_filter_handle_t handle)
100{
101 ClassHandler::ClassFilter *filter = (ClassHandler::ClassFilter *)handle;
102 filter->unregister();
103}
104
105int cls_call(cls_method_context_t hctx, const char *cls, const char *method,
106 char *indata, int datalen,
107 char **outdata, int *outdatalen)
108{
109 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
110 bufferlist idata;
111 vector<OSDOp> nops(1);
112 OSDOp& op = nops[0];
113 int r;
114
115 op.op.op = CEPH_OSD_OP_CALL;
116 op.op.cls.class_len = strlen(cls);
117 op.op.cls.method_len = strlen(method);
118 op.op.cls.indata_len = datalen;
119 op.indata.append(cls, op.op.cls.class_len);
120 op.indata.append(method, op.op.cls.method_len);
121 op.indata.append(indata, datalen);
122 r = (*pctx)->pg->do_osd_ops(*pctx, nops);
123 if (r < 0)
124 return r;
125
126 *outdata = (char *)malloc(op.outdata.length());
127 if (!*outdata)
128 return -ENOMEM;
129 memcpy(*outdata, op.outdata.c_str(), op.outdata.length());
130 *outdatalen = op.outdata.length();
131
132 return r;
133}
134
135int cls_getxattr(cls_method_context_t hctx, const char *name,
136 char **outdata, int *outdatalen)
137{
138 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
139 bufferlist name_data;
140 vector<OSDOp> nops(1);
141 OSDOp& op = nops[0];
142 int r;
143
144 op.op.op = CEPH_OSD_OP_GETXATTR;
145 op.indata.append(name);
146 op.op.xattr.name_len = strlen(name);
147 r = (*pctx)->pg->do_osd_ops(*pctx, nops);
148 if (r < 0)
149 return r;
150
151 *outdata = (char *)malloc(op.outdata.length());
152 if (!*outdata)
153 return -ENOMEM;
154 memcpy(*outdata, op.outdata.c_str(), op.outdata.length());
155 *outdatalen = op.outdata.length();
156
157 return r;
158}
159
160int cls_setxattr(cls_method_context_t hctx, const char *name,
161 const char *value, int val_len)
162{
163 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
164 bufferlist name_data;
165 vector<OSDOp> nops(1);
166 OSDOp& op = nops[0];
167 int r;
168
169 op.op.op = CEPH_OSD_OP_SETXATTR;
170 op.indata.append(name);
171 op.indata.append(value);
172 op.op.xattr.name_len = strlen(name);
173 op.op.xattr.value_len = val_len;
174 r = (*pctx)->pg->do_osd_ops(*pctx, nops);
175
176 return r;
177}
178
179int cls_read(cls_method_context_t hctx, int ofs, int len,
180 char **outdata, int *outdatalen)
181{
182 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
183 vector<OSDOp> ops(1);
184 ops[0].op.op = CEPH_OSD_OP_SYNC_READ;
185 ops[0].op.extent.offset = ofs;
186 ops[0].op.extent.length = len;
187 int r = (*pctx)->pg->do_osd_ops(*pctx, ops);
188 if (r < 0)
189 return r;
190
191 *outdata = (char *)malloc(ops[0].outdata.length());
192 if (!*outdata)
193 return -ENOMEM;
194 memcpy(*outdata, ops[0].outdata.c_str(), ops[0].outdata.length());
195 *outdatalen = ops[0].outdata.length();
196
197 return *outdatalen;
198}
199
200int cls_get_request_origin(cls_method_context_t hctx, entity_inst_t *origin)
201{
202 PrimaryLogPG::OpContext **pctx = static_cast<PrimaryLogPG::OpContext **>(hctx);
203 *origin = (*pctx)->op->get_req()->get_orig_source_inst();
204 return 0;
205}
206
207int cls_cxx_create(cls_method_context_t hctx, bool exclusive)
208{
209 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
210 vector<OSDOp> ops(1);
211 ops[0].op.op = CEPH_OSD_OP_CREATE;
212 ops[0].op.flags = (exclusive ? CEPH_OSD_OP_FLAG_EXCL : 0);
213 return (*pctx)->pg->do_osd_ops(*pctx, ops);
214}
215
216int cls_cxx_remove(cls_method_context_t hctx)
217{
218 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
219 vector<OSDOp> ops(1);
220 ops[0].op.op = CEPH_OSD_OP_DELETE;
221 return (*pctx)->pg->do_osd_ops(*pctx, ops);
222}
223
224int cls_cxx_stat(cls_method_context_t hctx, uint64_t *size, time_t *mtime)
225{
226 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
227 vector<OSDOp> ops(1);
228 int ret;
229 ops[0].op.op = CEPH_OSD_OP_STAT;
230 ret = (*pctx)->pg->do_osd_ops(*pctx, ops);
231 if (ret < 0)
232 return ret;
233 bufferlist::iterator iter = ops[0].outdata.begin();
234 utime_t ut;
235 uint64_t s;
236 try {
237 ::decode(s, iter);
238 ::decode(ut, iter);
239 } catch (buffer::error& err) {
240 return -EIO;
241 }
242 if (size)
243 *size = s;
244 if (mtime)
245 *mtime = ut.sec();
246 return 0;
247}
248
249int cls_cxx_stat2(cls_method_context_t hctx, uint64_t *size, ceph::real_time *mtime)
250{
251 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
252 vector<OSDOp> ops(1);
253 int ret;
254 ops[0].op.op = CEPH_OSD_OP_STAT;
255 ret = (*pctx)->pg->do_osd_ops(*pctx, ops);
256 if (ret < 0)
257 return ret;
258 bufferlist::iterator iter = ops[0].outdata.begin();
259 real_time ut;
260 uint64_t s;
261 try {
262 ::decode(s, iter);
263 ::decode(ut, iter);
264 } catch (buffer::error& err) {
265 return -EIO;
266 }
267 if (size)
268 *size = s;
269 if (mtime)
270 *mtime = ut;
271 return 0;
272}
273
274int cls_cxx_read(cls_method_context_t hctx, int ofs, int len, bufferlist *outbl)
275{
276 return cls_cxx_read2(hctx, ofs, len, outbl, 0);
277}
278
279int cls_cxx_read2(cls_method_context_t hctx, int ofs, int len,
280 bufferlist *outbl, uint32_t op_flags)
281{
282 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
283 vector<OSDOp> ops(1);
284 int ret;
285 ops[0].op.op = CEPH_OSD_OP_SYNC_READ;
286 ops[0].op.extent.offset = ofs;
287 ops[0].op.extent.length = len;
288 ops[0].op.flags = op_flags;
289 ret = (*pctx)->pg->do_osd_ops(*pctx, ops);
290 if (ret < 0)
291 return ret;
292 outbl->claim(ops[0].outdata);
293 return outbl->length();
294}
295
296int cls_cxx_write(cls_method_context_t hctx, int ofs, int len, bufferlist *inbl)
297{
298 return cls_cxx_write2(hctx, ofs, len, inbl, 0);
299}
300
301int cls_cxx_write2(cls_method_context_t hctx, int ofs, int len,
302 bufferlist *inbl, uint32_t op_flags)
303{
304 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
305 vector<OSDOp> ops(1);
306 ops[0].op.op = CEPH_OSD_OP_WRITE;
307 ops[0].op.extent.offset = ofs;
308 ops[0].op.extent.length = len;
309 ops[0].op.flags = op_flags;
310 ops[0].indata = *inbl;
311 return (*pctx)->pg->do_osd_ops(*pctx, ops);
312}
313
314int cls_cxx_write_full(cls_method_context_t hctx, bufferlist *inbl)
315{
316 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
317 vector<OSDOp> ops(1);
318 ops[0].op.op = CEPH_OSD_OP_WRITEFULL;
319 ops[0].op.extent.offset = 0;
320 ops[0].op.extent.length = inbl->length();
321 ops[0].indata = *inbl;
322 return (*pctx)->pg->do_osd_ops(*pctx, ops);
323}
324
325int cls_cxx_replace(cls_method_context_t hctx, int ofs, int len, bufferlist *inbl)
326{
327 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
328 vector<OSDOp> ops(2);
329 ops[0].op.op = CEPH_OSD_OP_TRUNCATE;
330 ops[0].op.extent.offset = 0;
331 ops[0].op.extent.length = 0;
332 ops[1].op.op = CEPH_OSD_OP_WRITE;
333 ops[1].op.extent.offset = ofs;
334 ops[1].op.extent.length = len;
335 ops[1].indata = *inbl;
336 return (*pctx)->pg->do_osd_ops(*pctx, ops);
337}
338
339int cls_cxx_getxattr(cls_method_context_t hctx, const char *name,
340 bufferlist *outbl)
341{
342 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
343 bufferlist name_data;
344 vector<OSDOp> nops(1);
345 OSDOp& op = nops[0];
346 int r;
347
348 op.op.op = CEPH_OSD_OP_GETXATTR;
349 op.indata.append(name);
350 op.op.xattr.name_len = strlen(name);
351 r = (*pctx)->pg->do_osd_ops(*pctx, nops);
352 if (r < 0)
353 return r;
354
355 outbl->claim(op.outdata);
356 return outbl->length();
357}
358
359int cls_cxx_getxattrs(cls_method_context_t hctx, map<string, bufferlist> *attrset)
360{
361 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
362 vector<OSDOp> nops(1);
363 OSDOp& op = nops[0];
364 int r;
365
366 op.op.op = CEPH_OSD_OP_GETXATTRS;
367 r = (*pctx)->pg->do_osd_ops(*pctx, nops);
368 if (r < 0)
369 return r;
370
371 bufferlist::iterator iter = op.outdata.begin();
372 try {
373 ::decode(*attrset, iter);
374 } catch (buffer::error& err) {
375 return -EIO;
376 }
377 return 0;
378}
379
380int cls_cxx_setxattr(cls_method_context_t hctx, const char *name,
381 bufferlist *inbl)
382{
383 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
384 bufferlist name_data;
385 vector<OSDOp> nops(1);
386 OSDOp& op = nops[0];
387 int r;
388
389 op.op.op = CEPH_OSD_OP_SETXATTR;
390 op.indata.append(name);
391 op.indata.append(*inbl);
392 op.op.xattr.name_len = strlen(name);
393 op.op.xattr.value_len = inbl->length();
394 r = (*pctx)->pg->do_osd_ops(*pctx, nops);
395
396 return r;
397}
398
399int cls_cxx_snap_revert(cls_method_context_t hctx, snapid_t snapid)
400{
401 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
402 vector<OSDOp> ops(1);
403 ops[0].op.op = CEPH_OSD_OP_ROLLBACK;
404 ops[0].op.snap.snapid = snapid;
405 return (*pctx)->pg->do_osd_ops(*pctx, ops);
406}
407
c07f9fc5
FG
408int cls_cxx_map_get_all_vals(cls_method_context_t hctx, map<string, bufferlist>* vals,
409 bool *more)
7c673cae
FG
410{
411 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
412 vector<OSDOp> ops(1);
413 OSDOp& op = ops[0];
414 int ret;
415
416 string start_after;
417 string filter_prefix;
418 uint64_t max = (uint64_t)-1;
419
420 ::encode(start_after, op.indata);
421 ::encode(max, op.indata);
422 ::encode(filter_prefix, op.indata);
423
424 op.op.op = CEPH_OSD_OP_OMAPGETVALS;
425
426 ret = (*pctx)->pg->do_osd_ops(*pctx, ops);
427 if (ret < 0)
428 return ret;
429
430 bufferlist::iterator iter = op.outdata.begin();
431 try {
432 ::decode(*vals, iter);
c07f9fc5 433 ::decode(*more, iter);
7c673cae
FG
434 } catch (buffer::error& err) {
435 return -EIO;
436 }
437 return vals->size();
438}
439
440int cls_cxx_map_get_keys(cls_method_context_t hctx, const string &start_obj,
c07f9fc5
FG
441 uint64_t max_to_get, set<string> *keys,
442 bool *more)
7c673cae
FG
443{
444 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
445 vector<OSDOp> ops(1);
446 OSDOp& op = ops[0];
447 int ret;
448
449 ::encode(start_obj, op.indata);
450 ::encode(max_to_get, op.indata);
451
452 op.op.op = CEPH_OSD_OP_OMAPGETKEYS;
453
454 ret = (*pctx)->pg->do_osd_ops(*pctx, ops);
455 if (ret < 0)
456 return ret;
457
458 bufferlist::iterator iter = op.outdata.begin();
459 try {
460 ::decode(*keys, iter);
c07f9fc5 461 ::decode(*more, iter);
7c673cae
FG
462 } catch (buffer::error& err) {
463 return -EIO;
464 }
465 return keys->size();
466}
467
468int cls_cxx_map_get_vals(cls_method_context_t hctx, const string &start_obj,
469 const string &filter_prefix, uint64_t max_to_get,
c07f9fc5 470 map<string, bufferlist> *vals, bool *more)
7c673cae
FG
471{
472 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
473 vector<OSDOp> ops(1);
474 OSDOp& op = ops[0];
475 int ret;
476
477 ::encode(start_obj, op.indata);
478 ::encode(max_to_get, op.indata);
479 ::encode(filter_prefix, op.indata);
480
481 op.op.op = CEPH_OSD_OP_OMAPGETVALS;
482
483 ret = (*pctx)->pg->do_osd_ops(*pctx, ops);
484 if (ret < 0)
485 return ret;
486
487 bufferlist::iterator iter = op.outdata.begin();
488 try {
489 ::decode(*vals, iter);
c07f9fc5 490 ::decode(*more, iter);
7c673cae
FG
491 } catch (buffer::error& err) {
492 return -EIO;
493 }
494 return vals->size();
495}
496
497int cls_cxx_map_read_header(cls_method_context_t hctx, bufferlist *outbl)
498{
499 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
500 vector<OSDOp> ops(1);
501 OSDOp& op = ops[0];
502 int ret;
503 op.op.op = CEPH_OSD_OP_OMAPGETHEADER;
504 ret = (*pctx)->pg->do_osd_ops(*pctx, ops);
505 if (ret < 0)
506 return ret;
507
508 outbl->claim(op.outdata);
509
510 return 0;
511}
512
513int cls_cxx_map_get_val(cls_method_context_t hctx, const string &key,
514 bufferlist *outbl)
515{
516 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
517 vector<OSDOp> ops(1);
518 OSDOp& op = ops[0];
519 int ret;
520
521 set<string> k;
522 k.insert(key);
523 ::encode(k, op.indata);
524
525 op.op.op = CEPH_OSD_OP_OMAPGETVALSBYKEYS;
526 ret = (*pctx)->pg->do_osd_ops(*pctx, ops);
527 if (ret < 0)
528 return ret;
529
530 bufferlist::iterator iter = op.outdata.begin();
531 try {
532 map<string, bufferlist> m;
533
534 ::decode(m, iter);
535 map<string, bufferlist>::iterator iter = m.begin();
536 if (iter == m.end())
537 return -ENOENT;
538
539 *outbl = iter->second;
540 } catch (buffer::error& e) {
541 return -EIO;
542 }
543 return 0;
544}
545
546int cls_cxx_map_set_val(cls_method_context_t hctx, const string &key,
547 bufferlist *inbl)
548{
549 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
550 vector<OSDOp> ops(1);
551 OSDOp& op = ops[0];
552 bufferlist& update_bl = op.indata;
553 map<string, bufferlist> m;
554 m[key] = *inbl;
555 ::encode(m, update_bl);
556
557 op.op.op = CEPH_OSD_OP_OMAPSETVALS;
558
559 return (*pctx)->pg->do_osd_ops(*pctx, ops);
560}
561
562int cls_cxx_map_set_vals(cls_method_context_t hctx,
563 const std::map<string, bufferlist> *map)
564{
565 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
566 vector<OSDOp> ops(1);
567 OSDOp& op = ops[0];
568 bufferlist& update_bl = op.indata;
569 ::encode(*map, update_bl);
570
571 op.op.op = CEPH_OSD_OP_OMAPSETVALS;
572
573 return (*pctx)->pg->do_osd_ops(*pctx, ops);
574}
575
576int cls_cxx_map_clear(cls_method_context_t hctx)
577{
578 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
579 vector<OSDOp> ops(1);
580 OSDOp& op = ops[0];
581
582 op.op.op = CEPH_OSD_OP_OMAPCLEAR;
583
584 return (*pctx)->pg->do_osd_ops(*pctx, ops);
585}
586
587int cls_cxx_map_write_header(cls_method_context_t hctx, bufferlist *inbl)
588{
589 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
590 vector<OSDOp> ops(1);
591 OSDOp& op = ops[0];
592 op.indata.claim(*inbl);
593
594 op.op.op = CEPH_OSD_OP_OMAPSETHEADER;
595
596 return (*pctx)->pg->do_osd_ops(*pctx, ops);
597}
598
599int cls_cxx_map_remove_key(cls_method_context_t hctx, const string &key)
600{
601 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
602 vector<OSDOp> ops(1);
603 OSDOp& op = ops[0];
604 bufferlist& update_bl = op.indata;
605 set<string> to_rm;
606 to_rm.insert(key);
607
608 ::encode(to_rm, update_bl);
609
610 op.op.op = CEPH_OSD_OP_OMAPRMKEYS;
611
612 return (*pctx)->pg->do_osd_ops(*pctx, ops);
613}
614
615int cls_cxx_list_watchers(cls_method_context_t hctx,
616 obj_list_watch_response_t *watchers)
617{
618 PrimaryLogPG::OpContext **pctx = (PrimaryLogPG::OpContext **)hctx;
619 vector<OSDOp> nops(1);
620 OSDOp& op = nops[0];
621 int r;
622
623 op.op.op = CEPH_OSD_OP_LIST_WATCHERS;
624 r = (*pctx)->pg->do_osd_ops(*pctx, nops);
625 if (r < 0)
626 return r;
627
628 bufferlist::iterator iter = op.outdata.begin();
629 try {
630 ::decode(*watchers, iter);
631 } catch (buffer::error& err) {
632 return -EIO;
633 }
634 return 0;
635}
636
637int cls_gen_random_bytes(char *buf, int size)
638{
639 return get_random_bytes(buf, size);
640}
641
642int cls_gen_rand_base64(char *dest, int size) /* size should be the required string size + 1 */
643{
644 char buf[size];
645 char tmp_dest[size + 4]; /* so that there's space for the extra '=' characters, and some */
646 int ret;
647
648 ret = cls_gen_random_bytes(buf, sizeof(buf));
649 if (ret < 0) {
650 lgeneric_derr(ch->cct) << "cannot get random bytes: " << ret << dendl;
651 return -1;
652 }
653
654 ret = ceph_armor(tmp_dest, &tmp_dest[sizeof(tmp_dest)],
655 (const char *)buf, ((const char *)buf) + ((size - 1) * 3 + 4 - 1) / 4);
656 if (ret < 0) {
657 lgeneric_derr(ch->cct) << "ceph_armor failed" << dendl;
658 return -1;
659 }
660 tmp_dest[ret] = '\0';
661 memcpy(dest, tmp_dest, size);
662 dest[size-1] = '\0';
663
664 return 0;
665}
666
667uint64_t cls_current_version(cls_method_context_t hctx)
668{
669 PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx;
670
671 return ctx->pg->info.last_user_version;
672}
673
674
675int cls_current_subop_num(cls_method_context_t hctx)
676{
677 PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx;
678
679 return ctx->current_osd_subop_num;
680}
681
682uint64_t cls_get_features(cls_method_context_t hctx)
683{
684 PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx;
685 return ctx->pg->get_osdmap()->get_up_osd_features();
686}
687
688uint64_t cls_get_client_features(cls_method_context_t hctx)
689{
690 PrimaryLogPG::OpContext *ctx = *(PrimaryLogPG::OpContext **)hctx;
691 return ctx->op->get_req()->get_connection()->get_features();
692}
693
694void cls_cxx_subop_version(cls_method_context_t hctx, string *s)
695{
696 if (!s)
697 return;
698
699 char buf[32];
700 uint64_t ver = cls_current_version(hctx);
701 int subop_num = cls_current_subop_num(hctx);
702 snprintf(buf, sizeof(buf), "%lld.%d", (long long)ver, subop_num);
703
704 *s = buf;
705}
706
707int cls_log(int level, const char *format, ...)
708{
709 int size = 256;
710 va_list ap;
711 while (1) {
712 char buf[size];
713 va_start(ap, format);
714 int n = vsnprintf(buf, size, format, ap);
715 va_end(ap);
716#define MAX_SIZE 8196
717 if ((n > -1 && n < size) || size > MAX_SIZE) {
718 ldout(ch->cct, level) << buf << dendl;
719 return n;
720 }
721 size *= 2;
722 }
723}