]> git.proxmox.com Git - ceph.git/blob - ceph/src/libcephfs.cc
8f88b387106c6446e507e18a0c2be6b006f6b733
[ceph.git] / ceph / src / libcephfs.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) 2009-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
15 #include <fcntl.h>
16 #include <iostream>
17 #include <string.h>
18 #include <string>
19
20 #include "auth/Crypto.h"
21 #include "client/Client.h"
22 #include "librados/RadosClient.h"
23 #include "common/async/context_pool.h"
24 #include "common/ceph_argparse.h"
25 #include "common/common_init.h"
26 #include "common/config.h"
27 #include "common/version.h"
28 #include "mon/MonClient.h"
29 #include "include/str_list.h"
30 #include "messages/MMonMap.h"
31 #include "msg/Messenger.h"
32 #include "include/ceph_assert.h"
33 #include "mds/MDSMap.h"
34
35 #include "include/cephfs/libcephfs.h"
36
37 #define DEFAULT_UMASK 002
38
39 static mode_t umask_cb(void *);
40 namespace {
41 // Set things up this way so we don't start up threads until mount and
42 // kill them off when the last mount goes away, but are tolerant to
43 // multiple mounts of overlapping duration.
44 std::shared_ptr<ceph::async::io_context_pool> get_icp(CephContext* cct)
45 {
46 static std::mutex m;
47 static std::weak_ptr<ceph::async::io_context_pool> icwp;
48
49
50 std::unique_lock l(m);
51
52 auto icp = icwp.lock();
53 if (icp)
54 return icp;
55
56 icp = std::make_shared<ceph::async::io_context_pool>();
57 icwp = icp;
58 icp->start(cct->_conf.get_val<std::uint64_t>("client_asio_thread_count"));
59 return icp;
60 }
61 }
62
63 struct ceph_mount_info
64 {
65 mode_t umask = DEFAULT_UMASK;
66 std::shared_ptr<ceph::async::io_context_pool> icp;
67 public:
68 explicit ceph_mount_info(CephContext *cct_)
69 : default_perms(),
70 mounted(false),
71 inited(false),
72 client(nullptr),
73 monclient(nullptr),
74 messenger(nullptr),
75 cct(cct_)
76 {
77 if (cct_) {
78 cct->get();
79 }
80 }
81
82 ~ceph_mount_info()
83 {
84 try {
85 shutdown();
86 if (cct) {
87 cct->put();
88 cct = nullptr;
89 }
90 }
91 catch (const std::exception& e) {
92 // we shouldn't get here, but if we do, we want to know about it.
93 lderr(cct) << "ceph_mount_info::~ceph_mount_info: caught exception: "
94 << e.what() << dendl;
95 }
96 catch (...) {
97 // ignore
98 }
99 }
100
101 int init()
102 {
103 int ret;
104
105 if (!cct->_log->is_started()) {
106 cct->_log->start();
107 }
108 icp = get_icp(cct);
109
110 {
111 MonClient mc_bootstrap(cct, icp->get_io_context());
112 ret = mc_bootstrap.get_monmap_and_config();
113 if (ret < 0)
114 return ret;
115 }
116
117 common_init_finish(cct);
118
119 //monmap
120 monclient = new MonClient(cct, icp->get_io_context());
121 ret = -CEPHFS_ERROR_MON_MAP_BUILD; //defined in libcephfs.h;
122 if (monclient->build_initial_monmap() < 0)
123 goto fail;
124
125 //network connection
126 messenger = Messenger::create_client_messenger(cct, "client");
127
128 //at last the client
129 ret = -CEPHFS_ERROR_NEW_CLIENT; //defined in libcephfs.h;
130 client = new StandaloneClient(messenger, monclient, icp->get_io_context());
131 if (!client)
132 goto fail;
133
134 ret = -CEPHFS_ERROR_MESSENGER_START; //defined in libcephfs.h;
135 if (messenger->start() != 0)
136 goto fail;
137
138 ret = client->init();
139 if (ret)
140 goto fail;
141
142 {
143 ceph_client_callback_args args = {};
144 args.handle = this;
145 args.umask_cb = umask_cb;
146 client->ll_register_callbacks(&args);
147 }
148
149 default_perms = Client::pick_my_perms(cct);
150 inited = true;
151 return 0;
152
153 fail:
154 shutdown();
155 return ret;
156 }
157
158 int select_filesystem(const std::string &fs_name_)
159 {
160 if (mounted) {
161 return -EISCONN;
162 }
163
164 fs_name = fs_name_;
165 return 0;
166 }
167
168 const std::string& get_filesystem(void)
169 {
170 return fs_name;
171 }
172
173 int mount(const std::string &mount_root, const UserPerm& perms)
174 {
175 int ret;
176
177 if (mounted)
178 return -EISCONN;
179
180 if (!inited) {
181 ret = init();
182 if (ret != 0) {
183 return ret;
184 }
185 }
186
187 ret = client->mount(mount_root, perms, false, fs_name);
188 if (ret) {
189 shutdown();
190 return ret;
191 } else {
192 mounted = true;
193 return 0;
194 }
195 }
196
197 int unmount()
198 {
199 if (!mounted)
200 return -ENOTCONN;
201 shutdown();
202 return 0;
203 }
204 int abort_conn()
205 {
206 if (mounted) {
207 client->abort_conn();
208 mounted = false;
209 }
210 return 0;
211 }
212
213 void shutdown()
214 {
215 if (mounted) {
216 client->unmount();
217 mounted = false;
218 }
219 if (inited) {
220 client->shutdown();
221 inited = false;
222 }
223 if (messenger) {
224 messenger->shutdown();
225 messenger->wait();
226 delete messenger;
227 messenger = nullptr;
228 }
229 icp.reset();
230 if (monclient) {
231 delete monclient;
232 monclient = nullptr;
233 }
234 if (client) {
235 delete client;
236 client = nullptr;
237 }
238 }
239
240 bool is_initialized() const
241 {
242 return inited;
243 }
244
245 bool is_mounted()
246 {
247 return mounted;
248 }
249
250 mode_t set_umask(mode_t umask)
251 {
252 this->umask = umask;
253 return umask;
254 }
255
256 std::string getaddrs()
257 {
258 CachedStackStringStream cos;
259 *cos << messenger->get_myaddrs();
260 return std::string(cos->strv());
261 }
262
263 int conf_read_file(const char *path_list)
264 {
265 int ret = cct->_conf.parse_config_files(path_list, nullptr, 0);
266 if (ret)
267 return ret;
268 cct->_conf.apply_changes(nullptr);
269 cct->_conf.complain_about_parse_error(cct);
270 return 0;
271 }
272
273 int conf_parse_argv(int argc, const char **argv)
274 {
275 int ret;
276 vector<const char*> args;
277 argv_to_vec(argc, argv, args);
278 ret = cct->_conf.parse_argv(args);
279 if (ret)
280 return ret;
281 cct->_conf.apply_changes(nullptr);
282 return 0;
283 }
284
285 int conf_parse_env(const char *name)
286 {
287 auto& conf = cct->_conf;
288 conf.parse_env(cct->get_module_type(), name);
289 conf.apply_changes(nullptr);
290 return 0;
291 }
292
293 int conf_set(const char *option, const char *value)
294 {
295 int ret = cct->_conf.set_val(option, value);
296 if (ret)
297 return ret;
298 cct->_conf.apply_changes(nullptr);
299 return 0;
300 }
301
302 int conf_get(const char *option, char *buf, size_t len)
303 {
304 char *tmp = buf;
305 return cct->_conf.get_val(option, &tmp, len);
306 }
307
308 Client *get_client()
309 {
310 return client;
311 }
312
313 const char *get_cwd(const UserPerm& perms)
314 {
315 client->getcwd(cwd, perms);
316 return cwd.c_str();
317 }
318
319 int chdir(const char *to, const UserPerm& perms)
320 {
321 return client->chdir(to, cwd, perms);
322 }
323
324 CephContext *get_ceph_context() const {
325 return cct;
326 }
327
328 UserPerm default_perms;
329 private:
330 bool mounted;
331 bool inited;
332 StandaloneClient *client;
333 MonClient *monclient;
334 Messenger *messenger;
335 CephContext *cct;
336 std::string cwd;
337 std::string fs_name;
338 };
339
340 static mode_t umask_cb(void *handle)
341 {
342 return ((struct ceph_mount_info *)handle)->umask;
343 }
344
345 static void do_out_buffer(bufferlist& outbl, char **outbuf, size_t *outbuflen)
346 {
347 if (outbuf) {
348 if (outbl.length() > 0) {
349 *outbuf = (char *)malloc(outbl.length());
350 memcpy(*outbuf, outbl.c_str(), outbl.length());
351 } else {
352 *outbuf = nullptr;
353 }
354 }
355 if (outbuflen)
356 *outbuflen = outbl.length();
357 }
358
359 static void do_out_buffer(string& outbl, char **outbuf, size_t *outbuflen)
360 {
361 if (outbuf) {
362 if (outbl.length() > 0) {
363 *outbuf = (char *)malloc(outbl.length());
364 memcpy(*outbuf, outbl.c_str(), outbl.length());
365 } else {
366 *outbuf = nullptr;
367 }
368 }
369 if (outbuflen)
370 *outbuflen = outbl.length();
371 }
372
373 extern "C" UserPerm *ceph_userperm_new(uid_t uid, gid_t gid, int ngids,
374 gid_t *gidlist)
375 {
376 return new (std::nothrow) UserPerm(uid, gid, ngids, gidlist);
377 }
378
379 extern "C" void ceph_userperm_destroy(UserPerm *perm)
380 {
381 delete perm;
382 }
383
384 extern "C" const char *ceph_version(int *pmajor, int *pminor, int *ppatch)
385 {
386 int major, minor, patch;
387 const char *v = ceph_version_to_str();
388
389 int n = sscanf(v, "%d.%d.%d", &major, &minor, &patch);
390 if (pmajor)
391 *pmajor = (n >= 1) ? major : 0;
392 if (pminor)
393 *pminor = (n >= 2) ? minor : 0;
394 if (ppatch)
395 *ppatch = (n >= 3) ? patch : 0;
396 return PROJECT_VERSION;
397 }
398
399 extern "C" int ceph_create_with_context(struct ceph_mount_info **cmount, CephContext *cct)
400 {
401 *cmount = new struct ceph_mount_info(cct);
402 return 0;
403 }
404
405 extern "C" int ceph_create_from_rados(struct ceph_mount_info **cmount,
406 rados_t cluster)
407 {
408 auto rados = (librados::RadosClient *) cluster;
409 auto cct = rados->cct;
410 return ceph_create_with_context(cmount, cct);
411 }
412
413 extern "C" int ceph_create(struct ceph_mount_info **cmount, const char * const id)
414 {
415 CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT);
416 if (id) {
417 iparams.name.set(CEPH_ENTITY_TYPE_CLIENT, id);
418 }
419
420 CephContext *cct = common_preinit(iparams, CODE_ENVIRONMENT_LIBRARY, 0);
421 cct->_conf.parse_env(cct->get_module_type()); // environment variables coverride
422 cct->_conf.apply_changes(nullptr);
423 int ret = ceph_create_with_context(cmount, cct);
424 cct->put();
425 cct = nullptr;
426 return ret;
427 }
428
429 extern "C" int ceph_unmount(struct ceph_mount_info *cmount)
430 {
431 return cmount->unmount();
432 }
433
434 extern "C" int ceph_abort_conn(struct ceph_mount_info *cmount)
435 {
436 return cmount->abort_conn();
437 }
438
439 extern "C" int ceph_release(struct ceph_mount_info *cmount)
440 {
441 if (cmount->is_mounted())
442 return -EISCONN;
443 delete cmount;
444 cmount = nullptr;
445 return 0;
446 }
447
448 extern "C" void ceph_shutdown(struct ceph_mount_info *cmount)
449 {
450 cmount->shutdown();
451 delete cmount;
452 cmount = nullptr;
453 }
454
455 extern "C" uint64_t ceph_get_instance_id(struct ceph_mount_info *cmount)
456 {
457 if (cmount->is_initialized())
458 return cmount->get_client()->get_nodeid().v;
459 return 0;
460 }
461
462 extern "C" int ceph_getaddrs(struct ceph_mount_info *cmount, char** addrs)
463 {
464 if (!cmount->is_initialized())
465 return -ENOTCONN;
466 auto s = cmount->getaddrs();
467 *addrs = strdup(s.c_str());
468 return 0;
469 }
470
471 extern "C" int ceph_conf_read_file(struct ceph_mount_info *cmount, const char *path)
472 {
473 return cmount->conf_read_file(path);
474 }
475
476 extern "C" mode_t ceph_umask(struct ceph_mount_info *cmount, mode_t mode)
477 {
478 return cmount->set_umask(mode);
479 }
480
481 extern "C" int ceph_conf_parse_argv(struct ceph_mount_info *cmount, int argc,
482 const char **argv)
483 {
484 return cmount->conf_parse_argv(argc, argv);
485 }
486
487 extern "C" int ceph_conf_parse_env(struct ceph_mount_info *cmount, const char *name)
488 {
489 return cmount->conf_parse_env(name);
490 }
491
492 extern "C" int ceph_conf_set(struct ceph_mount_info *cmount, const char *option,
493 const char *value)
494 {
495 return cmount->conf_set(option, value);
496 }
497
498 extern "C" int ceph_conf_get(struct ceph_mount_info *cmount, const char *option,
499 char *buf, size_t len)
500 {
501 if (!buf) {
502 return -EINVAL;
503 }
504 return cmount->conf_get(option, buf, len);
505 }
506
507 extern "C" int ceph_mds_command(struct ceph_mount_info *cmount,
508 const char *mds_spec,
509 const char **cmd,
510 size_t cmdlen,
511 const char *inbuf, size_t inbuflen,
512 char **outbuf, size_t *outbuflen,
513 char **outsbuf, size_t *outsbuflen)
514 {
515 bufferlist inbl;
516 bufferlist outbl;
517 std::vector<string> cmdv;
518 std::string outs;
519
520 if (!cmount->is_initialized()) {
521 return -ENOTCONN;
522 }
523
524 // Construct inputs
525 for (size_t i = 0; i < cmdlen; ++i) {
526 cmdv.push_back(cmd[i]);
527 }
528 inbl.append(inbuf, inbuflen);
529
530 // Issue remote command
531 C_SaferCond cond;
532 int r = cmount->get_client()->mds_command(
533 mds_spec,
534 cmdv, inbl,
535 &outbl, &outs,
536 &cond);
537
538 if (r != 0) {
539 goto out;
540 }
541
542 // Wait for completion
543 r = cond.wait();
544
545 // Construct outputs
546 do_out_buffer(outbl, outbuf, outbuflen);
547 do_out_buffer(outs, outsbuf, outsbuflen);
548
549 out:
550 return r;
551 }
552
553 extern "C" int ceph_init(struct ceph_mount_info *cmount)
554 {
555 return cmount->init();
556 }
557
558 extern "C" int ceph_select_filesystem(struct ceph_mount_info *cmount,
559 const char *fs_name)
560 {
561 if (fs_name == nullptr) {
562 return -EINVAL;
563 }
564
565 return cmount->select_filesystem(fs_name);
566 }
567
568 extern "C" int ceph_mount(struct ceph_mount_info *cmount, const char *root)
569 {
570 std::string mount_root;
571 if (root)
572 mount_root = root;
573 return cmount->mount(mount_root, cmount->default_perms);
574 }
575
576 extern "C" int ceph_is_mounted(struct ceph_mount_info *cmount)
577 {
578 return cmount->is_mounted() ? 1 : 0;
579 }
580
581 extern "C" struct UserPerm *ceph_mount_perms(struct ceph_mount_info *cmount)
582 {
583 return &cmount->default_perms;
584 }
585
586 extern "C" int64_t ceph_get_fs_cid(struct ceph_mount_info *cmount)
587 {
588 if (!cmount->is_mounted())
589 return -ENOTCONN;
590 return cmount->get_client()->get_fs_cid();
591 }
592
593 extern "C" int ceph_mount_perms_set(struct ceph_mount_info *cmount,
594 struct UserPerm *perms)
595 {
596 if (cmount->is_mounted())
597 return -EISCONN;
598 cmount->default_perms = *perms;
599 return 0;
600 }
601
602 extern "C" int ceph_statfs(struct ceph_mount_info *cmount, const char *path,
603 struct statvfs *stbuf)
604 {
605 if (!cmount->is_mounted())
606 return -ENOTCONN;
607 return cmount->get_client()->statfs(path, stbuf, cmount->default_perms);
608 }
609
610 extern "C" int ceph_get_local_osd(struct ceph_mount_info *cmount)
611 {
612 if (!cmount->is_mounted())
613 return -ENOTCONN;
614 return cmount->get_client()->get_local_osd();
615 }
616
617 extern "C" const char* ceph_getcwd(struct ceph_mount_info *cmount)
618 {
619 return cmount->get_cwd(cmount->default_perms);
620 }
621
622 extern "C" int ceph_chdir (struct ceph_mount_info *cmount, const char *s)
623 {
624 if (!cmount->is_mounted())
625 return -ENOTCONN;
626 return cmount->chdir(s, cmount->default_perms);
627 }
628
629 extern "C" int ceph_opendir(struct ceph_mount_info *cmount,
630 const char *name, struct ceph_dir_result **dirpp)
631 {
632 if (!cmount->is_mounted())
633 return -ENOTCONN;
634 return cmount->get_client()->opendir(name, (dir_result_t **)dirpp, cmount->default_perms);
635 }
636
637 extern "C" int ceph_closedir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
638 {
639 if (!cmount->is_mounted())
640 return -ENOTCONN;
641 return cmount->get_client()->closedir(reinterpret_cast<dir_result_t*>(dirp));
642 }
643
644 extern "C" struct dirent * ceph_readdir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
645 {
646 if (!cmount->is_mounted()) {
647 /* Client::readdir also sets errno to signal errors. */
648 errno = ENOTCONN;
649 return nullptr;
650 }
651 return cmount->get_client()->readdir(reinterpret_cast<dir_result_t*>(dirp));
652 }
653
654 extern "C" int ceph_readdir_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, struct dirent *de)
655 {
656 if (!cmount->is_mounted())
657 return -ENOTCONN;
658 return cmount->get_client()->readdir_r(reinterpret_cast<dir_result_t*>(dirp), de);
659 }
660
661 extern "C" int ceph_readdirplus_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp,
662 struct dirent *de, struct ceph_statx *stx, unsigned want,
663 unsigned flags, struct Inode **out)
664 {
665 if (!cmount->is_mounted())
666 return -ENOTCONN;
667 if (flags & ~CEPH_REQ_FLAG_MASK)
668 return -EINVAL;
669 return cmount->get_client()->readdirplus_r(reinterpret_cast<dir_result_t*>(dirp), de, stx, want, flags, out);
670 }
671
672 extern "C" int ceph_getdents(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp,
673 char *buf, int buflen)
674 {
675 if (!cmount->is_mounted())
676 return -ENOTCONN;
677 return cmount->get_client()->getdents(reinterpret_cast<dir_result_t*>(dirp), buf, buflen);
678 }
679
680 extern "C" int ceph_getdnames(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp,
681 char *buf, int buflen)
682 {
683 if (!cmount->is_mounted())
684 return -ENOTCONN;
685 return cmount->get_client()->getdnames(reinterpret_cast<dir_result_t*>(dirp), buf, buflen);
686 }
687
688 extern "C" void ceph_rewinddir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
689 {
690 if (!cmount->is_mounted())
691 return;
692 cmount->get_client()->rewinddir(reinterpret_cast<dir_result_t*>(dirp));
693 }
694
695 extern "C" int64_t ceph_telldir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
696 {
697 if (!cmount->is_mounted())
698 return -ENOTCONN;
699 return cmount->get_client()->telldir(reinterpret_cast<dir_result_t*>(dirp));
700 }
701
702 extern "C" void ceph_seekdir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, int64_t offset)
703 {
704 if (!cmount->is_mounted())
705 return;
706 cmount->get_client()->seekdir(reinterpret_cast<dir_result_t*>(dirp), offset);
707 }
708
709 extern "C" int ceph_may_delete(struct ceph_mount_info *cmount, const char *path)
710 {
711 if (!cmount->is_mounted())
712 return -ENOTCONN;
713 return cmount->get_client()->may_delete(path, cmount->default_perms);
714 }
715
716 extern "C" int ceph_link (struct ceph_mount_info *cmount, const char *existing,
717 const char *newname)
718 {
719 if (!cmount->is_mounted())
720 return -ENOTCONN;
721 return cmount->get_client()->link(existing, newname, cmount->default_perms);
722 }
723
724 extern "C" int ceph_unlink(struct ceph_mount_info *cmount, const char *path)
725 {
726 if (!cmount->is_mounted())
727 return -ENOTCONN;
728 return cmount->get_client()->unlink(path, cmount->default_perms);
729 }
730
731 extern "C" int ceph_rename(struct ceph_mount_info *cmount, const char *from,
732 const char *to)
733 {
734 if (!cmount->is_mounted())
735 return -ENOTCONN;
736 return cmount->get_client()->rename(from, to, cmount->default_perms);
737 }
738
739 // dirs
740 extern "C" int ceph_mkdir(struct ceph_mount_info *cmount, const char *path, mode_t mode)
741 {
742 if (!cmount->is_mounted())
743 return -ENOTCONN;
744 return cmount->get_client()->mkdir(path, mode, cmount->default_perms);
745 }
746
747 extern "C" int ceph_mksnap(struct ceph_mount_info *cmount, const char *path, const char *name,
748 mode_t mode, struct snap_metadata *snap_metadata, size_t nr_snap_metadata)
749 {
750 if (!cmount->is_mounted())
751 return -ENOTCONN;
752 size_t i = 0;
753 std::map<std::string, std::string> metadata;
754 while (i < nr_snap_metadata) {
755 metadata.emplace(snap_metadata[i].key, snap_metadata[i].value);
756 ++i;
757 }
758 return cmount->get_client()->mksnap(path, name, cmount->default_perms, mode, metadata);
759 }
760
761 extern "C" int ceph_rmsnap(struct ceph_mount_info *cmount, const char *path, const char *name)
762 {
763 if (!cmount->is_mounted())
764 return -ENOTCONN;
765 return cmount->get_client()->rmsnap(path, name, cmount->default_perms, true);
766 }
767
768 extern "C" int ceph_mkdirs(struct ceph_mount_info *cmount, const char *path, mode_t mode)
769 {
770 if (!cmount->is_mounted())
771 return -ENOTCONN;
772 return cmount->get_client()->mkdirs(path, mode, cmount->default_perms);
773 }
774
775 extern "C" int ceph_rmdir(struct ceph_mount_info *cmount, const char *path)
776 {
777 if (!cmount->is_mounted())
778 return -ENOTCONN;
779 return cmount->get_client()->rmdir(path, cmount->default_perms);
780 }
781
782 // symlinks
783 extern "C" int ceph_readlink(struct ceph_mount_info *cmount, const char *path,
784 char *buf, int64_t size)
785 {
786 if (!cmount->is_mounted())
787 return -ENOTCONN;
788 return cmount->get_client()->readlink(path, buf, size, cmount->default_perms);
789 }
790
791 extern "C" int ceph_symlink(struct ceph_mount_info *cmount, const char *existing,
792 const char *newname)
793 {
794 if (!cmount->is_mounted())
795 return -ENOTCONN;
796 return cmount->get_client()->symlink(existing, newname, cmount->default_perms);
797 }
798
799 extern "C" int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_statx *stx,
800 unsigned int want, unsigned int flags)
801 {
802 if (!cmount->is_mounted())
803 return -ENOTCONN;
804 if (flags & ~CEPH_REQ_FLAG_MASK)
805 return -EINVAL;
806 return cmount->get_client()->fstatx(fd, stx, cmount->default_perms,
807 want, flags);
808 }
809
810 extern "C" int ceph_statx(struct ceph_mount_info *cmount, const char *path,
811 struct ceph_statx *stx, unsigned int want, unsigned int flags)
812 {
813 if (!cmount->is_mounted())
814 return -ENOTCONN;
815 if (flags & ~CEPH_REQ_FLAG_MASK)
816 return -EINVAL;
817 return cmount->get_client()->statx(path, stx, cmount->default_perms,
818 want, flags);
819 }
820
821 extern "C" int ceph_fsetattrx(struct ceph_mount_info *cmount, int fd,
822 struct ceph_statx *stx, int mask)
823 {
824 if (!cmount->is_mounted())
825 return -ENOTCONN;
826 return cmount->get_client()->fsetattrx(fd, stx, mask, cmount->default_perms);
827 }
828
829 extern "C" int ceph_setattrx(struct ceph_mount_info *cmount, const char *relpath,
830 struct ceph_statx *stx, int mask, int flags)
831 {
832 if (!cmount->is_mounted())
833 return -ENOTCONN;
834 if (flags & ~CEPH_REQ_FLAG_MASK)
835 return -EINVAL;
836 return cmount->get_client()->setattrx(relpath, stx, mask,
837 cmount->default_perms, flags);
838 }
839
840 // *xattr() calls supporting samba/vfs
841 extern "C" int ceph_getxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size)
842 {
843 if (!cmount->is_mounted())
844 return -ENOTCONN;
845
846 return cmount->get_client()->getxattr(path, name, value, size, cmount->default_perms);
847 }
848
849 extern "C" int ceph_lgetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size)
850 {
851 if (!cmount->is_mounted())
852 return -ENOTCONN;
853 return cmount->get_client()->lgetxattr(path, name, value, size, cmount->default_perms);
854 }
855
856 extern "C" int ceph_fgetxattr(struct ceph_mount_info *cmount, int fd, const char *name, void *value, size_t size)
857 {
858 if (!cmount->is_mounted())
859 return -ENOTCONN;
860 return cmount->get_client()->fgetxattr(fd, name, value, size, cmount->default_perms);
861 }
862
863
864 extern "C" int ceph_listxattr(struct ceph_mount_info *cmount, const char *path, char *list, size_t size)
865 {
866 if (!cmount->is_mounted())
867 return -ENOTCONN;
868 return cmount->get_client()->listxattr(path, list, size, cmount->default_perms);
869 }
870
871 extern "C" int ceph_llistxattr(struct ceph_mount_info *cmount, const char *path, char *list, size_t size)
872 {
873 if (!cmount->is_mounted())
874 return -ENOTCONN;
875 return cmount->get_client()->llistxattr(path, list, size, cmount->default_perms);
876 }
877
878 extern "C" int ceph_flistxattr(struct ceph_mount_info *cmount, int fd, char *list, size_t size)
879 {
880 if (!cmount->is_mounted())
881 return -ENOTCONN;
882 return cmount->get_client()->flistxattr(fd, list, size, cmount->default_perms);
883 }
884
885 extern "C" int ceph_removexattr(struct ceph_mount_info *cmount, const char *path, const char *name)
886 {
887 if (!cmount->is_mounted())
888 return -ENOTCONN;
889 return cmount->get_client()->removexattr(path, name, cmount->default_perms);
890 }
891
892 extern "C" int ceph_lremovexattr(struct ceph_mount_info *cmount, const char *path, const char *name)
893 {
894 if (!cmount->is_mounted())
895 return -ENOTCONN;
896 return cmount->get_client()->lremovexattr(path, name, cmount->default_perms);
897 }
898
899 extern "C" int ceph_fremovexattr(struct ceph_mount_info *cmount, int fd, const char *name)
900 {
901 if (!cmount->is_mounted())
902 return -ENOTCONN;
903 return cmount->get_client()->fremovexattr(fd, name, cmount->default_perms);
904 }
905
906 extern "C" int ceph_setxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags)
907 {
908 if (!cmount->is_mounted())
909 return -ENOTCONN;
910 return cmount->get_client()->setxattr(path, name, value, size, flags, cmount->default_perms);
911 }
912
913 extern "C" int ceph_lsetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags)
914 {
915 if (!cmount->is_mounted())
916 return -ENOTCONN;
917 return cmount->get_client()->lsetxattr(path, name, value, size, flags, cmount->default_perms);
918 }
919
920 extern "C" int ceph_fsetxattr(struct ceph_mount_info *cmount, int fd, const char *name, const void *value, size_t size, int flags)
921 {
922 if (!cmount->is_mounted())
923 return -ENOTCONN;
924 return cmount->get_client()->fsetxattr(fd, name, value, size, flags, cmount->default_perms);
925 }
926 /* end xattr support */
927
928 extern "C" int ceph_stat(struct ceph_mount_info *cmount, const char *path, struct stat *stbuf)
929 {
930 if (!cmount->is_mounted())
931 return -ENOTCONN;
932 return cmount->get_client()->stat(path, stbuf, cmount->default_perms);
933 }
934
935 extern "C" int ceph_fstat(struct ceph_mount_info *cmount, int fd, struct stat *stbuf)
936 {
937 if (!cmount->is_mounted())
938 return -ENOTCONN;
939 return cmount->get_client()->fstat(fd, stbuf, cmount->default_perms);
940 }
941
942 extern int ceph_lstat(struct ceph_mount_info *cmount, const char *path, struct stat *stbuf)
943 {
944 if (!cmount->is_mounted())
945 return -ENOTCONN;
946 return cmount->get_client()->lstat(path, stbuf, cmount->default_perms);
947 }
948
949 extern "C" int ceph_chmod(struct ceph_mount_info *cmount, const char *path, mode_t mode)
950 {
951 if (!cmount->is_mounted())
952 return -ENOTCONN;
953 return cmount->get_client()->chmod(path, mode, cmount->default_perms);
954 }
955 extern "C" int ceph_lchmod(struct ceph_mount_info *cmount, const char *path, mode_t mode)
956 {
957 if (!cmount->is_mounted())
958 return -ENOTCONN;
959 return cmount->get_client()->lchmod(path, mode, cmount->default_perms);
960 }
961 extern "C" int ceph_fchmod(struct ceph_mount_info *cmount, int fd, mode_t mode)
962 {
963 if (!cmount->is_mounted())
964 return -ENOTCONN;
965 return cmount->get_client()->fchmod(fd, mode, cmount->default_perms);
966 }
967 extern "C" int ceph_chown(struct ceph_mount_info *cmount, const char *path,
968 int uid, int gid)
969 {
970 if (!cmount->is_mounted())
971 return -ENOTCONN;
972 return cmount->get_client()->chown(path, uid, gid, cmount->default_perms);
973 }
974 extern "C" int ceph_fchown(struct ceph_mount_info *cmount, int fd,
975 int uid, int gid)
976 {
977 if (!cmount->is_mounted())
978 return -ENOTCONN;
979 return cmount->get_client()->fchown(fd, uid, gid, cmount->default_perms);
980 }
981 extern "C" int ceph_lchown(struct ceph_mount_info *cmount, const char *path,
982 int uid, int gid)
983 {
984 if (!cmount->is_mounted())
985 return -ENOTCONN;
986 return cmount->get_client()->lchown(path, uid, gid, cmount->default_perms);
987 }
988
989
990 extern "C" int ceph_utime(struct ceph_mount_info *cmount, const char *path,
991 struct utimbuf *buf)
992 {
993 if (!cmount->is_mounted())
994 return -ENOTCONN;
995 return cmount->get_client()->utime(path, buf, cmount->default_perms);
996 }
997
998 extern "C" int ceph_futime(struct ceph_mount_info *cmount, int fd,
999 struct utimbuf *buf)
1000 {
1001 if (!cmount->is_mounted())
1002 return -ENOTCONN;
1003 return cmount->get_client()->futime(fd, buf, cmount->default_perms);
1004 }
1005
1006 extern "C" int ceph_utimes(struct ceph_mount_info *cmount, const char *path,
1007 struct timeval times[2])
1008 {
1009 if (!cmount->is_mounted())
1010 return -ENOTCONN;
1011 return cmount->get_client()->utimes(path, times, cmount->default_perms);
1012 }
1013
1014 extern "C" int ceph_lutimes(struct ceph_mount_info *cmount, const char *path,
1015 struct timeval times[2])
1016 {
1017 if (!cmount->is_mounted())
1018 return -ENOTCONN;
1019 return cmount->get_client()->lutimes(path, times, cmount->default_perms);
1020 }
1021
1022 extern "C" int ceph_futimes(struct ceph_mount_info *cmount, int fd,
1023 struct timeval times[2])
1024 {
1025 if (!cmount->is_mounted())
1026 return -ENOTCONN;
1027 return cmount->get_client()->futimes(fd, times, cmount->default_perms);
1028 }
1029
1030 extern "C" int ceph_futimens(struct ceph_mount_info *cmount, int fd,
1031 struct timespec times[2])
1032 {
1033 if (!cmount->is_mounted())
1034 return -ENOTCONN;
1035 return cmount->get_client()->futimens(fd, times, cmount->default_perms);
1036 }
1037
1038 extern "C" int ceph_flock(struct ceph_mount_info *cmount, int fd, int operation,
1039 uint64_t owner)
1040 {
1041 if (!cmount->is_mounted())
1042 return -ENOTCONN;
1043 return cmount->get_client()->flock(fd, operation, owner);
1044 }
1045
1046 extern "C" int ceph_truncate(struct ceph_mount_info *cmount, const char *path,
1047 int64_t size)
1048 {
1049 if (!cmount->is_mounted())
1050 return -ENOTCONN;
1051 return cmount->get_client()->truncate(path, size, cmount->default_perms);
1052 }
1053
1054 // file ops
1055 extern "C" int ceph_mknod(struct ceph_mount_info *cmount, const char *path,
1056 mode_t mode, dev_t rdev)
1057 {
1058 if (!cmount->is_mounted())
1059 return -ENOTCONN;
1060 return cmount->get_client()->mknod(path, mode, cmount->default_perms, rdev);
1061 }
1062
1063 extern "C" int ceph_open(struct ceph_mount_info *cmount, const char *path,
1064 int flags, mode_t mode)
1065 {
1066 if (!cmount->is_mounted())
1067 return -ENOTCONN;
1068 return cmount->get_client()->open(path, flags, cmount->default_perms, mode);
1069 }
1070
1071 extern "C" int ceph_open_layout(struct ceph_mount_info *cmount, const char *path, int flags,
1072 mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool)
1073 {
1074 if (!cmount->is_mounted())
1075 return -ENOTCONN;
1076 return cmount->get_client()->open(path, flags, cmount->default_perms, mode,
1077 stripe_unit, stripe_count,
1078 object_size, data_pool);
1079 }
1080
1081 extern "C" int ceph_close(struct ceph_mount_info *cmount, int fd)
1082 {
1083 if (!cmount->is_mounted())
1084 return -ENOTCONN;
1085 return cmount->get_client()->close(fd);
1086 }
1087
1088 extern "C" int64_t ceph_lseek(struct ceph_mount_info *cmount, int fd,
1089 int64_t offset, int whence)
1090 {
1091 if (!cmount->is_mounted())
1092 return -ENOTCONN;
1093 return cmount->get_client()->lseek(fd, offset, whence);
1094 }
1095
1096 extern "C" int ceph_read(struct ceph_mount_info *cmount, int fd, char *buf,
1097 int64_t size, int64_t offset)
1098 {
1099 if (!cmount->is_mounted())
1100 return -ENOTCONN;
1101 return cmount->get_client()->read(fd, buf, size, offset);
1102 }
1103
1104 extern "C" int ceph_preadv(struct ceph_mount_info *cmount, int fd,
1105 const struct iovec *iov, int iovcnt, int64_t offset)
1106 {
1107 if (!cmount->is_mounted())
1108 return -ENOTCONN;
1109 return cmount->get_client()->preadv(fd, iov, iovcnt, offset);
1110 }
1111
1112 extern "C" int ceph_write(struct ceph_mount_info *cmount, int fd, const char *buf,
1113 int64_t size, int64_t offset)
1114 {
1115 if (!cmount->is_mounted())
1116 return -ENOTCONN;
1117 return cmount->get_client()->write(fd, buf, size, offset);
1118 }
1119
1120 extern "C" int ceph_pwritev(struct ceph_mount_info *cmount, int fd,
1121 const struct iovec *iov, int iovcnt, int64_t offset)
1122 {
1123 if (!cmount->is_mounted())
1124 return -ENOTCONN;
1125 return cmount->get_client()->pwritev(fd, iov, iovcnt, offset);
1126 }
1127
1128 extern "C" int ceph_ftruncate(struct ceph_mount_info *cmount, int fd, int64_t size)
1129 {
1130 if (!cmount->is_mounted())
1131 return -ENOTCONN;
1132 return cmount->get_client()->ftruncate(fd, size, cmount->default_perms);
1133 }
1134
1135 extern "C" int ceph_fsync(struct ceph_mount_info *cmount, int fd, int syncdataonly)
1136 {
1137 if (!cmount->is_mounted())
1138 return -ENOTCONN;
1139 return cmount->get_client()->fsync(fd, syncdataonly);
1140 }
1141
1142 extern "C" int ceph_fallocate(struct ceph_mount_info *cmount, int fd, int mode,
1143 int64_t offset, int64_t length)
1144 {
1145 if (!cmount->is_mounted())
1146 return -ENOTCONN;
1147 return cmount->get_client()->fallocate(fd, mode, offset, length);
1148 }
1149
1150 extern "C" int ceph_lazyio(class ceph_mount_info *cmount,
1151 int fd, int enable)
1152 {
1153 return (cmount->get_client()->lazyio(fd, enable));
1154 }
1155
1156 extern "C" int ceph_lazyio_propagate(class ceph_mount_info *cmount,
1157 int fd, int64_t offset, size_t count)
1158 {
1159 if (!cmount->is_mounted())
1160 return -ENOTCONN;
1161 return (cmount->get_client()->lazyio_propagate(fd, offset, count));
1162 }
1163
1164 extern "C" int ceph_lazyio_synchronize(class ceph_mount_info *cmount,
1165 int fd, int64_t offset, size_t count)
1166 {
1167 if (!cmount->is_mounted())
1168 return -ENOTCONN;
1169 return (cmount->get_client()->lazyio_synchronize(fd, offset, count));
1170 }
1171
1172
1173 extern "C" int ceph_sync_fs(struct ceph_mount_info *cmount)
1174 {
1175 if (!cmount->is_mounted())
1176 return -ENOTCONN;
1177 return cmount->get_client()->sync_fs();
1178 }
1179
1180 extern "C" int ceph_get_file_stripe_unit(struct ceph_mount_info *cmount, int fh)
1181 {
1182 file_layout_t l;
1183 int r;
1184
1185 if (!cmount->is_mounted())
1186 return -ENOTCONN;
1187 r = cmount->get_client()->fdescribe_layout(fh, &l);
1188 if (r < 0)
1189 return r;
1190 return l.stripe_unit;
1191 }
1192
1193 extern "C" int ceph_get_path_stripe_unit(struct ceph_mount_info *cmount, const char *path)
1194 {
1195 file_layout_t l;
1196 int r;
1197
1198 if (!cmount->is_mounted())
1199 return -ENOTCONN;
1200 r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1201 if (r < 0)
1202 return r;
1203 return l.stripe_unit;
1204 }
1205
1206 extern "C" int ceph_get_file_stripe_count(struct ceph_mount_info *cmount, int fh)
1207 {
1208 file_layout_t l;
1209 int r;
1210
1211 if (!cmount->is_mounted())
1212 return -ENOTCONN;
1213 r = cmount->get_client()->fdescribe_layout(fh, &l);
1214 if (r < 0)
1215 return r;
1216 return l.stripe_count;
1217 }
1218
1219 extern "C" int ceph_get_path_stripe_count(struct ceph_mount_info *cmount, const char *path)
1220 {
1221 file_layout_t l;
1222 int r;
1223
1224 if (!cmount->is_mounted())
1225 return -ENOTCONN;
1226 r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1227 if (r < 0)
1228 return r;
1229 return l.stripe_count;
1230 }
1231
1232 extern "C" int ceph_get_file_object_size(struct ceph_mount_info *cmount, int fh)
1233 {
1234 file_layout_t l;
1235 int r;
1236
1237 if (!cmount->is_mounted())
1238 return -ENOTCONN;
1239 r = cmount->get_client()->fdescribe_layout(fh, &l);
1240 if (r < 0)
1241 return r;
1242 return l.object_size;
1243 }
1244
1245 extern "C" int ceph_get_path_object_size(struct ceph_mount_info *cmount, const char *path)
1246 {
1247 file_layout_t l;
1248 int r;
1249
1250 if (!cmount->is_mounted())
1251 return -ENOTCONN;
1252 r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1253 if (r < 0)
1254 return r;
1255 return l.object_size;
1256 }
1257
1258 extern "C" int ceph_get_file_pool(struct ceph_mount_info *cmount, int fh)
1259 {
1260 file_layout_t l;
1261 int r;
1262
1263 if (!cmount->is_mounted())
1264 return -ENOTCONN;
1265 r = cmount->get_client()->fdescribe_layout(fh, &l);
1266 if (r < 0)
1267 return r;
1268 return l.pool_id;
1269 }
1270
1271 extern "C" int ceph_get_path_pool(struct ceph_mount_info *cmount, const char *path)
1272 {
1273 file_layout_t l;
1274 int r;
1275
1276 if (!cmount->is_mounted())
1277 return -ENOTCONN;
1278 r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1279 if (r < 0)
1280 return r;
1281 return l.pool_id;
1282 }
1283
1284 extern "C" int ceph_get_file_pool_name(struct ceph_mount_info *cmount, int fh, char *buf, size_t len)
1285 {
1286 file_layout_t l;
1287 int r;
1288
1289 if (!cmount->is_mounted())
1290 return -ENOTCONN;
1291 r = cmount->get_client()->fdescribe_layout(fh, &l);
1292 if (r < 0)
1293 return r;
1294 string name = cmount->get_client()->get_pool_name(l.pool_id);
1295 if (len == 0)
1296 return name.length();
1297 if (name.length() > len)
1298 return -ERANGE;
1299 strncpy(buf, name.c_str(), len);
1300 return name.length();
1301 }
1302
1303 extern "C" int ceph_get_pool_name(struct ceph_mount_info *cmount, int pool, char *buf, size_t len)
1304 {
1305 if (!cmount->is_mounted())
1306 return -ENOTCONN;
1307 string name = cmount->get_client()->get_pool_name(pool);
1308 if (len == 0)
1309 return name.length();
1310 if (name.length() > len)
1311 return -ERANGE;
1312 strncpy(buf, name.c_str(), len);
1313 return name.length();
1314 }
1315
1316 extern "C" int ceph_get_path_pool_name(struct ceph_mount_info *cmount, const char *path, char *buf, size_t len)
1317 {
1318 file_layout_t l;
1319 int r;
1320
1321 if (!cmount->is_mounted())
1322 return -ENOTCONN;
1323 r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1324 if (r < 0)
1325 return r;
1326 string name = cmount->get_client()->get_pool_name(l.pool_id);
1327 if (len == 0)
1328 return name.length();
1329 if (name.length() > len)
1330 return -ERANGE;
1331 strncpy(buf, name.c_str(), len);
1332 return name.length();
1333 }
1334
1335 extern "C" int ceph_get_default_data_pool_name(struct ceph_mount_info *cmount, char *buf, size_t len)
1336 {
1337 if (!cmount->is_mounted())
1338 return -ENOTCONN;
1339 int64_t pool_id = cmount->get_client()->get_default_pool_id();
1340
1341 string name = cmount->get_client()->get_pool_name(pool_id);
1342 if (len == 0)
1343 return name.length();
1344 if (name.length() > len)
1345 return -ERANGE;
1346 strncpy(buf, name.c_str(), len);
1347 return name.length();
1348 }
1349
1350 extern "C" int ceph_get_file_layout(struct ceph_mount_info *cmount, int fh, int *stripe_unit, int *stripe_count, int *object_size, int *pg_pool)
1351 {
1352 file_layout_t l;
1353 int r;
1354
1355 if (!cmount->is_mounted())
1356 return -ENOTCONN;
1357 r = cmount->get_client()->fdescribe_layout(fh, &l);
1358 if (r < 0)
1359 return r;
1360 if (stripe_unit)
1361 *stripe_unit = l.stripe_unit;
1362 if (stripe_count)
1363 *stripe_count = l.stripe_count;
1364 if (object_size)
1365 *object_size = l.object_size;
1366 if (pg_pool)
1367 *pg_pool = l.pool_id;
1368 return 0;
1369 }
1370
1371 extern "C" int ceph_get_path_layout(struct ceph_mount_info *cmount, const char *path, int *stripe_unit, int *stripe_count, int *object_size, int *pg_pool)
1372 {
1373 file_layout_t l;
1374 int r;
1375
1376 if (!cmount->is_mounted())
1377 return -ENOTCONN;
1378 r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1379 if (r < 0)
1380 return r;
1381 if (stripe_unit)
1382 *stripe_unit = l.stripe_unit;
1383 if (stripe_count)
1384 *stripe_count = l.stripe_count;
1385 if (object_size)
1386 *object_size = l.object_size;
1387 if (pg_pool)
1388 *pg_pool = l.pool_id;
1389 return 0;
1390 }
1391
1392 extern "C" int ceph_get_file_replication(struct ceph_mount_info *cmount, int fh)
1393 {
1394 file_layout_t l;
1395 int r;
1396
1397 if (!cmount->is_mounted())
1398 return -ENOTCONN;
1399 r = cmount->get_client()->fdescribe_layout(fh, &l);
1400 if (r < 0)
1401 return r;
1402 int rep = cmount->get_client()->get_pool_replication(l.pool_id);
1403 return rep;
1404 }
1405
1406 extern "C" int ceph_get_path_replication(struct ceph_mount_info *cmount, const char *path)
1407 {
1408 file_layout_t l;
1409 int r;
1410
1411 if (!cmount->is_mounted())
1412 return -ENOTCONN;
1413 r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1414 if (r < 0)
1415 return r;
1416 int rep = cmount->get_client()->get_pool_replication(l.pool_id);
1417 return rep;
1418 }
1419
1420 extern "C" int ceph_set_default_file_stripe_unit(struct ceph_mount_info *cmount,
1421 int stripe)
1422 {
1423 // this option no longer exists
1424 return -EOPNOTSUPP;
1425 }
1426
1427 extern "C" int ceph_set_default_file_stripe_count(struct ceph_mount_info *cmount,
1428 int count)
1429 {
1430 // this option no longer exists
1431 return -EOPNOTSUPP;
1432 }
1433
1434 extern "C" int ceph_set_default_object_size(struct ceph_mount_info *cmount, int size)
1435 {
1436 // this option no longer exists
1437 return -EOPNOTSUPP;
1438 }
1439
1440 extern "C" int ceph_set_default_file_replication(struct ceph_mount_info *cmount,
1441 int replication)
1442 {
1443 // this option no longer exists
1444 return -EOPNOTSUPP;
1445 }
1446
1447 extern "C" int ceph_set_default_preferred_pg(struct ceph_mount_info *cmount, int osd)
1448 {
1449 // this option no longer exists
1450 return -EOPNOTSUPP;
1451 }
1452
1453 extern "C" int ceph_get_file_extent_osds(struct ceph_mount_info *cmount, int fh,
1454 int64_t offset, int64_t *length, int *osds, int nosds)
1455 {
1456 if (nosds < 0)
1457 return -EINVAL;
1458
1459 if (!cmount->is_mounted())
1460 return -ENOTCONN;
1461
1462 vector<int> vosds;
1463 int ret = cmount->get_client()->get_file_extent_osds(fh, offset, length, vosds);
1464 if (ret < 0)
1465 return ret;
1466
1467 if (!nosds)
1468 return vosds.size();
1469
1470 if ((int)vosds.size() > nosds)
1471 return -ERANGE;
1472
1473 for (int i = 0; i < (int)vosds.size(); i++)
1474 osds[i] = vosds[i];
1475
1476 return vosds.size();
1477 }
1478
1479 extern "C" int ceph_get_osd_crush_location(struct ceph_mount_info *cmount,
1480 int osd, char *path, size_t len)
1481 {
1482 if (!cmount->is_mounted())
1483 return -ENOTCONN;
1484
1485 if (!path && len)
1486 return -EINVAL;
1487
1488 vector<pair<string, string> > loc;
1489 int ret = cmount->get_client()->get_osd_crush_location(osd, loc);
1490 if (ret)
1491 return ret;
1492
1493 size_t needed = 0;
1494 size_t cur = 0;
1495 vector<pair<string, string> >::iterator it;
1496 for (it = loc.begin(); it != loc.end(); ++it) {
1497 string& type = it->first;
1498 string& name = it->second;
1499 needed += type.size() + name.size() + 2;
1500 if (needed <= len) {
1501 if (path)
1502 strcpy(path + cur, type.c_str());
1503 cur += type.size() + 1;
1504 if (path)
1505 strcpy(path + cur, name.c_str());
1506 cur += name.size() + 1;
1507 }
1508 }
1509
1510 if (len == 0)
1511 return needed;
1512
1513 if (needed > len)
1514 return -ERANGE;
1515
1516 return needed;
1517 }
1518
1519 extern "C" int ceph_get_osd_addr(struct ceph_mount_info *cmount, int osd,
1520 struct sockaddr_storage *addr)
1521 {
1522 if (!cmount->is_mounted())
1523 return -ENOTCONN;
1524
1525 if (!addr)
1526 return -EINVAL;
1527
1528 entity_addr_t address;
1529 int ret = cmount->get_client()->get_osd_addr(osd, address);
1530 if (ret < 0)
1531 return ret;
1532
1533 *addr = address.get_sockaddr_storage();
1534
1535 return 0;
1536 }
1537
1538 extern "C" int ceph_get_file_stripe_address(struct ceph_mount_info *cmount, int fh,
1539 int64_t offset, struct sockaddr_storage *addr, int naddr)
1540 {
1541 vector<entity_addr_t> address;
1542 unsigned i;
1543 int r;
1544
1545 if (naddr < 0)
1546 return -EINVAL;
1547
1548 if (!cmount->is_mounted())
1549 return -ENOTCONN;
1550
1551 r = cmount->get_client()->get_file_stripe_address(fh, offset, address);
1552 if (r < 0)
1553 return r;
1554
1555 for (i = 0; i < (unsigned)naddr && i < address.size(); i++)
1556 addr[i] = address[i].get_sockaddr_storage();
1557
1558 /* naddr == 0: drop through and return actual size */
1559 if (naddr && (address.size() > (unsigned)naddr))
1560 return -ERANGE;
1561
1562 return address.size();
1563 }
1564
1565 extern "C" int ceph_localize_reads(struct ceph_mount_info *cmount, int val)
1566 {
1567 if (!cmount->is_mounted())
1568 return -ENOTCONN;
1569 if (!val)
1570 cmount->get_client()->clear_filer_flags(CEPH_OSD_FLAG_LOCALIZE_READS);
1571 else
1572 cmount->get_client()->set_filer_flags(CEPH_OSD_FLAG_LOCALIZE_READS);
1573 return 0;
1574 }
1575
1576 extern "C" CephContext *ceph_get_mount_context(struct ceph_mount_info *cmount)
1577 {
1578 return cmount->get_ceph_context();
1579 }
1580
1581 extern "C" int ceph_debug_get_fd_caps(struct ceph_mount_info *cmount, int fd)
1582 {
1583 if (!cmount->is_mounted())
1584 return -ENOTCONN;
1585 return cmount->get_client()->get_caps_issued(fd);
1586 }
1587
1588 extern "C" int ceph_debug_get_file_caps(struct ceph_mount_info *cmount, const char *path)
1589 {
1590 if (!cmount->is_mounted())
1591 return -ENOTCONN;
1592 return cmount->get_client()->get_caps_issued(path, cmount->default_perms);
1593 }
1594
1595 extern "C" int ceph_get_stripe_unit_granularity(struct ceph_mount_info *cmount)
1596 {
1597 if (!cmount->is_mounted())
1598 return -ENOTCONN;
1599 return CEPH_MIN_STRIPE_UNIT;
1600 }
1601
1602 extern "C" int ceph_get_pool_id(struct ceph_mount_info *cmount, const char *pool_name)
1603 {
1604 if (!cmount->is_mounted())
1605 return -ENOTCONN;
1606
1607 if (!pool_name || !pool_name[0])
1608 return -EINVAL;
1609
1610 /* negative range reserved for errors */
1611 int64_t pool_id = cmount->get_client()->get_pool_id(pool_name);
1612 if (pool_id > 0x7fffffff)
1613 return -ERANGE;
1614
1615 /* get_pool_id error codes fit in int */
1616 return (int)pool_id;
1617 }
1618
1619 extern "C" int ceph_get_pool_replication(struct ceph_mount_info *cmount,
1620 int pool_id)
1621 {
1622 if (!cmount->is_mounted())
1623 return -ENOTCONN;
1624 return cmount->get_client()->get_pool_replication(pool_id);
1625 }
1626 /* Low-level exports */
1627
1628 extern "C" int ceph_ll_lookup_root(struct ceph_mount_info *cmount,
1629 Inode **parent)
1630 {
1631 *parent = cmount->get_client()->get_root();
1632 if (*parent)
1633 return 0;
1634 return -EFAULT;
1635 }
1636
1637 extern "C" struct Inode *ceph_ll_get_inode(class ceph_mount_info *cmount,
1638 vinodeno_t vino)
1639 {
1640 return (cmount->get_client())->ll_get_inode(vino);
1641 }
1642
1643
1644 extern "C" int ceph_ll_lookup_vino(
1645 struct ceph_mount_info *cmount,
1646 vinodeno_t vino,
1647 Inode **inode)
1648 {
1649 return (cmount->get_client())->ll_lookup_vino(vino, cmount->default_perms, inode);
1650 }
1651
1652 /**
1653 * Populates the client cache with the requested inode, and its
1654 * parent dentry.
1655 */
1656 extern "C" int ceph_ll_lookup_inode(
1657 struct ceph_mount_info *cmount,
1658 struct inodeno_t ino,
1659 Inode **inode)
1660 {
1661 return (cmount->get_client())->ll_lookup_inode(ino, cmount->default_perms, inode);
1662 }
1663
1664 extern "C" int ceph_ll_lookup(struct ceph_mount_info *cmount,
1665 Inode *parent, const char *name, Inode **out,
1666 struct ceph_statx *stx, unsigned want,
1667 unsigned flags, const UserPerm *perms)
1668 {
1669 if (flags & ~CEPH_REQ_FLAG_MASK)
1670 return -EINVAL;
1671 return (cmount->get_client())->ll_lookupx(parent, name, out, stx, want,
1672 flags, *perms);
1673 }
1674
1675 extern "C" int ceph_ll_put(class ceph_mount_info *cmount, Inode *in)
1676 {
1677 return (cmount->get_client()->ll_put(in));
1678 }
1679
1680 extern "C" int ceph_ll_forget(class ceph_mount_info *cmount, Inode *in,
1681 int count)
1682 {
1683 return (cmount->get_client()->ll_forget(in, count));
1684 }
1685
1686 extern "C" int ceph_ll_walk(struct ceph_mount_info *cmount, const char* name, Inode **i,
1687 struct ceph_statx *stx, unsigned int want, unsigned int flags,
1688 const UserPerm *perms)
1689 {
1690 if (flags & ~CEPH_REQ_FLAG_MASK)
1691 return -EINVAL;
1692 return(cmount->get_client()->ll_walk(name, i, stx, want, flags, *perms));
1693 }
1694
1695 extern "C" int ceph_ll_getattr(class ceph_mount_info *cmount,
1696 Inode *in, struct ceph_statx *stx,
1697 unsigned int want, unsigned int flags,
1698 const UserPerm *perms)
1699 {
1700 if (flags & ~CEPH_REQ_FLAG_MASK)
1701 return -EINVAL;
1702 return (cmount->get_client()->ll_getattrx(in, stx, want, flags, *perms));
1703 }
1704
1705 extern "C" int ceph_ll_setattr(class ceph_mount_info *cmount,
1706 Inode *in, struct ceph_statx *stx,
1707 int mask, const UserPerm *perms)
1708 {
1709 return (cmount->get_client()->ll_setattrx(in, stx, mask, *perms));
1710 }
1711
1712 extern "C" int ceph_ll_open(class ceph_mount_info *cmount, Inode *in,
1713 int flags, Fh **fh, const UserPerm *perms)
1714 {
1715 return (cmount->get_client()->ll_open(in, flags, fh, *perms));
1716 }
1717
1718 extern "C" int ceph_ll_read(class ceph_mount_info *cmount, Fh* filehandle,
1719 int64_t off, uint64_t len, char* buf)
1720 {
1721 bufferlist bl;
1722 int r = 0;
1723
1724 r = cmount->get_client()->ll_read(filehandle, off, len, &bl);
1725 if (r >= 0)
1726 {
1727 bl.begin().copy(bl.length(), buf);
1728 r = bl.length();
1729 }
1730 return r;
1731 }
1732
1733 extern "C" int ceph_ll_read_block(class ceph_mount_info *cmount,
1734 Inode *in, uint64_t blockid,
1735 char* buf, uint64_t offset,
1736 uint64_t length,
1737 struct ceph_file_layout* layout)
1738 {
1739 file_layout_t l;
1740 int r = (cmount->get_client()->ll_read_block(in, blockid, buf, offset,
1741 length, &l));
1742 l.to_legacy(layout);
1743 return r;
1744 }
1745
1746 extern "C" int ceph_ll_write_block(class ceph_mount_info *cmount,
1747 Inode *in, uint64_t blockid,
1748 char *buf, uint64_t offset,
1749 uint64_t length,
1750 struct ceph_file_layout *layout,
1751 uint64_t snapseq, uint32_t sync)
1752 {
1753 file_layout_t l;
1754 int r = (cmount->get_client()->ll_write_block(in, blockid, buf, offset,
1755 length, &l, snapseq, sync));
1756 l.to_legacy(layout);
1757 return r;
1758 }
1759
1760 extern "C" int ceph_ll_commit_blocks(class ceph_mount_info *cmount,
1761 Inode *in, uint64_t offset,
1762 uint64_t range)
1763 {
1764 return (cmount->get_client()->ll_commit_blocks(in, offset, range));
1765 }
1766
1767 extern "C" int ceph_ll_fsync(class ceph_mount_info *cmount,
1768 Fh *fh, int syncdataonly)
1769 {
1770 return (cmount->get_client()->ll_fsync(fh, syncdataonly));
1771 }
1772
1773 extern "C" int ceph_ll_sync_inode(class ceph_mount_info *cmount,
1774 Inode *in, int syncdataonly)
1775 {
1776 return (cmount->get_client()->ll_sync_inode(in, syncdataonly));
1777 }
1778
1779 extern "C" int ceph_ll_fallocate(class ceph_mount_info *cmount, Fh *fh,
1780 int mode, int64_t offset, int64_t length)
1781 {
1782 return cmount->get_client()->ll_fallocate(fh, mode, offset, length);
1783 }
1784
1785 extern "C" off_t ceph_ll_lseek(class ceph_mount_info *cmount,
1786 Fh *fh, off_t offset, int whence)
1787 {
1788 return (cmount->get_client()->ll_lseek(fh, offset, whence));
1789 }
1790
1791 extern "C" int ceph_ll_write(class ceph_mount_info *cmount,
1792 Fh *fh, int64_t off, uint64_t len,
1793 const char *data)
1794 {
1795 return (cmount->get_client()->ll_write(fh, off, len, data));
1796 }
1797
1798 extern "C" int64_t ceph_ll_readv(class ceph_mount_info *cmount,
1799 struct Fh *fh, const struct iovec *iov,
1800 int iovcnt, int64_t off)
1801 {
1802 return (cmount->get_client()->ll_readv(fh, iov, iovcnt, off));
1803 }
1804
1805 extern "C" int64_t ceph_ll_writev(class ceph_mount_info *cmount,
1806 struct Fh *fh, const struct iovec *iov,
1807 int iovcnt, int64_t off)
1808 {
1809 return (cmount->get_client()->ll_writev(fh, iov, iovcnt, off));
1810 }
1811
1812 extern "C" int ceph_ll_close(class ceph_mount_info *cmount, Fh* fh)
1813 {
1814 return (cmount->get_client()->ll_release(fh));
1815 }
1816
1817 extern "C" int ceph_ll_create(class ceph_mount_info *cmount,
1818 Inode *parent, const char *name, mode_t mode,
1819 int oflags, Inode **outp, Fh **fhp,
1820 struct ceph_statx *stx, unsigned want,
1821 unsigned lflags, const UserPerm *perms)
1822 {
1823 if (lflags & ~CEPH_REQ_FLAG_MASK)
1824 return -EINVAL;
1825 return (cmount->get_client())->ll_createx(parent, name, mode, oflags, outp,
1826 fhp, stx, want, lflags, *perms);
1827 }
1828
1829 extern "C" int ceph_ll_mknod(class ceph_mount_info *cmount, Inode *parent,
1830 const char *name, mode_t mode, dev_t rdev,
1831 Inode **out, struct ceph_statx *stx,
1832 unsigned want, unsigned flags,
1833 const UserPerm *perms)
1834 {
1835 if (flags & ~CEPH_REQ_FLAG_MASK)
1836 return -EINVAL;
1837 return (cmount->get_client())->ll_mknodx(parent, name, mode, rdev,
1838 out, stx, want, flags, *perms);
1839 }
1840
1841 extern "C" int ceph_ll_mkdir(class ceph_mount_info *cmount, Inode *parent,
1842 const char *name, mode_t mode, Inode **out,
1843 struct ceph_statx *stx, unsigned want,
1844 unsigned flags, const UserPerm *perms)
1845 {
1846 if (flags & ~CEPH_REQ_FLAG_MASK)
1847 return -EINVAL;
1848 return cmount->get_client()->ll_mkdirx(parent, name, mode, out, stx, want,
1849 flags, *perms);
1850 }
1851
1852 extern "C" int ceph_ll_link(class ceph_mount_info *cmount,
1853 Inode *in, Inode *newparent,
1854 const char *name, const UserPerm *perms)
1855 {
1856 return cmount->get_client()->ll_link(in, newparent, name, *perms);
1857 }
1858
1859 extern "C" int ceph_ll_opendir(class ceph_mount_info *cmount,
1860 Inode *in,
1861 struct ceph_dir_result **dirpp,
1862 const UserPerm *perms)
1863 {
1864 return (cmount->get_client()->ll_opendir(in, O_RDONLY, (dir_result_t**) dirpp,
1865 *perms));
1866 }
1867
1868 extern "C" int ceph_ll_releasedir(class ceph_mount_info *cmount,
1869 ceph_dir_result *dir)
1870 {
1871 return cmount->get_client()->ll_releasedir(reinterpret_cast<dir_result_t*>(dir));
1872 }
1873
1874 extern "C" int ceph_ll_rename(class ceph_mount_info *cmount,
1875 Inode *parent, const char *name,
1876 Inode *newparent, const char *newname,
1877 const UserPerm *perms)
1878 {
1879 return cmount->get_client()->ll_rename(parent, name, newparent,
1880 newname, *perms);
1881 }
1882
1883 extern "C" int ceph_ll_unlink(class ceph_mount_info *cmount, Inode *in,
1884 const char *name, const UserPerm *perms)
1885 {
1886 return cmount->get_client()->ll_unlink(in, name, *perms);
1887 }
1888
1889 extern "C" int ceph_ll_statfs(class ceph_mount_info *cmount,
1890 Inode *in, struct statvfs *stbuf)
1891 {
1892 return (cmount->get_client()->ll_statfs(in, stbuf, cmount->default_perms));
1893 }
1894
1895 extern "C" int ceph_ll_readlink(class ceph_mount_info *cmount, Inode *in,
1896 char *buf, size_t bufsiz,
1897 const UserPerm *perms)
1898 {
1899 return cmount->get_client()->ll_readlink(in, buf, bufsiz, *perms);
1900 }
1901
1902 extern "C" int ceph_ll_symlink(class ceph_mount_info *cmount,
1903 Inode *in, const char *name,
1904 const char *value, Inode **out,
1905 struct ceph_statx *stx, unsigned want,
1906 unsigned flags, const UserPerm *perms)
1907 {
1908 if (flags & ~CEPH_REQ_FLAG_MASK)
1909 return -EINVAL;
1910 return (cmount->get_client()->ll_symlinkx(in, name, value, out, stx, want,
1911 flags, *perms));
1912 }
1913
1914 extern "C" int ceph_ll_rmdir(class ceph_mount_info *cmount,
1915 Inode *in, const char *name,
1916 const UserPerm *perms)
1917 {
1918 return cmount->get_client()->ll_rmdir(in, name, *perms);
1919 }
1920
1921 extern "C" int ceph_ll_getxattr(class ceph_mount_info *cmount,
1922 Inode *in, const char *name, void *value,
1923 size_t size, const UserPerm *perms)
1924 {
1925 return (cmount->get_client()->ll_getxattr(in, name, value, size, *perms));
1926 }
1927
1928 extern "C" int ceph_ll_listxattr(struct ceph_mount_info *cmount,
1929 Inode *in, char *list,
1930 size_t buf_size, size_t *list_size,
1931 const UserPerm *perms)
1932 {
1933 int res = cmount->get_client()->ll_listxattr(in, list, buf_size, *perms);
1934 if (res >= 0) {
1935 *list_size = (size_t)res;
1936 return 0;
1937 }
1938 return res;
1939 }
1940
1941 extern "C" int ceph_ll_setxattr(class ceph_mount_info *cmount,
1942 Inode *in, const char *name,
1943 const void *value, size_t size,
1944 int flags, const UserPerm *perms)
1945 {
1946 return (cmount->get_client()->ll_setxattr(in, name, value, size, flags, *perms));
1947 }
1948
1949 extern "C" int ceph_ll_removexattr(class ceph_mount_info *cmount,
1950 Inode *in, const char *name,
1951 const UserPerm *perms)
1952 {
1953 return (cmount->get_client()->ll_removexattr(in, name, *perms));
1954 }
1955
1956 extern "C" int ceph_ll_getlk(struct ceph_mount_info *cmount,
1957 Fh *fh, struct flock *fl, uint64_t owner)
1958 {
1959 return (cmount->get_client()->ll_getlk(fh, fl, owner));
1960 }
1961
1962 extern "C" int ceph_ll_setlk(struct ceph_mount_info *cmount,
1963 Fh *fh, struct flock *fl, uint64_t owner,
1964 int sleep)
1965 {
1966 return (cmount->get_client()->ll_setlk(fh, fl, owner, sleep));
1967 }
1968
1969 extern "C" int ceph_ll_lazyio(class ceph_mount_info *cmount,
1970 Fh *fh, int enable)
1971 {
1972 return (cmount->get_client()->ll_lazyio(fh, enable));
1973 }
1974
1975 extern "C" int ceph_ll_delegation(struct ceph_mount_info *cmount, Fh *fh,
1976 unsigned cmd, ceph_deleg_cb_t cb, void *priv)
1977 {
1978 return (cmount->get_client()->ll_delegation(fh, cmd, cb, priv));
1979 }
1980
1981 extern "C" uint32_t ceph_ll_stripe_unit(class ceph_mount_info *cmount,
1982 Inode *in)
1983 {
1984 return (cmount->get_client()->ll_stripe_unit(in));
1985 }
1986
1987 extern "C" uint32_t ceph_ll_file_layout(class ceph_mount_info *cmount,
1988 Inode *in,
1989 struct ceph_file_layout *layout)
1990 {
1991 file_layout_t l;
1992 int r = (cmount->get_client()->ll_file_layout(in, &l));
1993 l.to_legacy(layout);
1994 return r;
1995 }
1996
1997 uint64_t ceph_ll_snap_seq(class ceph_mount_info *cmount, Inode *in)
1998 {
1999 return (cmount->get_client()->ll_snap_seq(in));
2000 }
2001
2002 extern "C" int ceph_ll_get_stripe_osd(class ceph_mount_info *cmount,
2003 Inode *in, uint64_t blockno,
2004 struct ceph_file_layout* layout)
2005 {
2006 file_layout_t l;
2007 int r = (cmount->get_client()->ll_get_stripe_osd(in, blockno, &l));
2008 l.to_legacy(layout);
2009 return r;
2010 }
2011
2012 extern "C" int ceph_ll_num_osds(class ceph_mount_info *cmount)
2013 {
2014 return (cmount->get_client()->ll_num_osds());
2015 }
2016
2017 extern "C" int ceph_ll_osdaddr(class ceph_mount_info *cmount,
2018 int osd, uint32_t *addr)
2019 {
2020 return (cmount->get_client()->ll_osdaddr(osd, addr));
2021 }
2022
2023 extern "C" uint64_t ceph_ll_get_internal_offset(class ceph_mount_info *cmount,
2024 Inode *in,
2025 uint64_t blockno)
2026 {
2027 return (cmount->get_client()->ll_get_internal_offset(in, blockno));
2028 }
2029
2030 extern "C" void ceph_buffer_free(char *buf)
2031 {
2032 if (buf) {
2033 free(buf);
2034 }
2035 }
2036
2037 extern "C" uint32_t ceph_get_cap_return_timeout(class ceph_mount_info *cmount)
2038 {
2039 if (!cmount->is_mounted())
2040 return 0;
2041 return cmount->get_client()->mdsmap->get_session_autoclose().sec();
2042 }
2043
2044 extern "C" int ceph_set_deleg_timeout(class ceph_mount_info *cmount, uint32_t timeout)
2045 {
2046 if (!cmount->is_mounted())
2047 return -ENOTCONN;
2048 return cmount->get_client()->set_deleg_timeout(timeout);
2049 }
2050
2051 extern "C" void ceph_set_session_timeout(class ceph_mount_info *cmount, unsigned timeout)
2052 {
2053 cmount->get_client()->set_session_timeout(timeout);
2054 }
2055
2056 extern "C" void ceph_set_uuid(class ceph_mount_info *cmount, const char *uuid)
2057 {
2058 cmount->get_client()->set_uuid(std::string(uuid));
2059 }
2060
2061 extern "C" int ceph_start_reclaim(class ceph_mount_info *cmount,
2062 const char *uuid, unsigned flags)
2063 {
2064 if (!cmount->is_initialized()) {
2065 int ret = cmount->init();
2066 if (ret != 0)
2067 return ret;
2068 }
2069 return cmount->get_client()->start_reclaim(std::string(uuid), flags,
2070 cmount->get_filesystem());
2071 }
2072
2073 extern "C" void ceph_finish_reclaim(class ceph_mount_info *cmount)
2074 {
2075 cmount->get_client()->finish_reclaim();
2076 }
2077
2078 extern "C" void ceph_ll_register_callbacks(class ceph_mount_info *cmount,
2079 struct ceph_client_callback_args *args)
2080 {
2081 cmount->get_client()->ll_register_callbacks(args);
2082
2083 }
2084
2085
2086 extern "C" int ceph_get_snap_info(struct ceph_mount_info *cmount,
2087 const char *path, struct snap_info *snap_info) {
2088 Client::SnapInfo info;
2089 int r = cmount->get_client()->get_snap_info(path, cmount->default_perms, &info);
2090 if (r < 0) {
2091 return r;
2092 }
2093
2094 size_t i = 0;
2095 auto nr_metadata = info.metadata.size();
2096
2097 snap_info->id = info.id.val;
2098 snap_info->nr_snap_metadata = nr_metadata;
2099 if (nr_metadata) {
2100 snap_info->snap_metadata = (struct snap_metadata *)calloc(nr_metadata, sizeof(struct snap_metadata));
2101 if (!snap_info->snap_metadata) {
2102 return -ENOMEM;
2103 }
2104
2105 // fill with key, value pairs
2106 for (auto &[key, value] : info.metadata) {
2107 // len(key) + '\0' + len(value) + '\0'
2108 char *kvp = (char *)malloc(key.size() + value.size() + 2);
2109 if (!kvp) {
2110 break;
2111 }
2112 char *_key = kvp;
2113 char *_value = kvp + key.size() + 1;
2114
2115 memcpy(_key, key.c_str(), key.size());
2116 _key[key.size()] = '\0';
2117 memcpy(_value, value.c_str(), value.size());
2118 _value[value.size()] = '\0';
2119
2120 snap_info->snap_metadata[i].key = _key;
2121 snap_info->snap_metadata[i].value = _value;
2122 ++i;
2123 }
2124 }
2125
2126 if (nr_metadata && i != nr_metadata) {
2127 ceph_free_snap_info_buffer(snap_info);
2128 return -ENOMEM;
2129 }
2130
2131 return 0;
2132 }
2133
2134 extern "C" void ceph_free_snap_info_buffer(struct snap_info *snap_info) {
2135 for (size_t i = 0; i < snap_info->nr_snap_metadata; ++i) {
2136 free((void *)snap_info->snap_metadata[i].key); // malloc'd memory is key+value composite
2137 }
2138 free(snap_info->snap_metadata);
2139 }