Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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/Mutex.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/assert.h"
33
34 #include "include/cephfs/libcephfs.h"
35
36
37 struct ceph_mount_info
38 {
39 public:
40   explicit ceph_mount_info(CephContext *cct_)
41     : default_perms(),
42       mounted(false),
43       inited(false),
44       client(NULL),
45       monclient(NULL),
46       messenger(NULL),
47       cct(cct_)
48   {
49     if (cct_ != nullptr) {
50       cct->get();
51     }
52   }
53
54   ~ceph_mount_info()
55   {
56     try {
57       shutdown();
58       if (cct) {
59         cct->put();
60         cct = NULL;
61       }
62     }
63     catch (const std::exception& e) {
64       // we shouldn't get here, but if we do, we want to know about it.
65       lderr(cct) << "ceph_mount_info::~ceph_mount_info: caught exception: "
66                  << e.what() << dendl;
67     }
68     catch (...) {
69       // ignore
70     }
71   }
72
73   int init()
74   {
75     common_init_finish(cct);
76
77     int ret;
78
79     //monmap
80     monclient = new MonClient(cct);
81     ret = -CEPHFS_ERROR_MON_MAP_BUILD; //defined in libcephfs.h;
82     if (monclient->build_initial_monmap() < 0)
83       goto fail;
84
85     //network connection
86     messenger = Messenger::create_client_messenger(cct, "client");
87
88     //at last the client
89     ret = -CEPHFS_ERROR_NEW_CLIENT; //defined in libcephfs.h;
90     client = new StandaloneClient(messenger, monclient);
91     if (!client)
92       goto fail;
93
94     ret = -CEPHFS_ERROR_MESSENGER_START; //defined in libcephfs.h;
95     if (messenger->start() != 0)
96       goto fail;
97
98     ret = client->init();
99     if (ret)
100       goto fail;
101
102     default_perms = Client::pick_my_perms(cct);
103     inited = true;
104     return 0;
105
106     fail:
107     shutdown();
108     return ret;
109   }
110
111   int mount(const std::string &mount_root, const UserPerm& perms)
112   {
113     int ret;
114     
115     if (mounted)
116       return -EISCONN;
117
118     if (!inited) {
119       ret = init();
120       if (ret != 0) {
121         return ret;
122       }
123     }
124
125     ret = client->mount(mount_root, perms);
126     if (ret) {
127       shutdown();
128       return ret;
129     } else {
130       mounted = true;
131       return 0;
132     }
133   }
134
135   int unmount()
136   {
137     if (!mounted)
138       return -ENOTCONN;
139     shutdown();
140     return 0;
141   }
142
143   void shutdown()
144   {
145     if (mounted) {
146       client->unmount();
147       mounted = false;
148     }
149     if (inited) {
150       client->shutdown();
151       inited = false;
152     }
153     if (messenger) {
154       messenger->shutdown();
155       messenger->wait();
156       delete messenger;
157       messenger = NULL;
158     }
159     if (monclient) {
160       delete monclient;
161       monclient = NULL;
162     }
163     if (client) {
164       delete client;
165       client = NULL;
166     }
167   }
168
169   bool is_initialized() const
170   {
171     return inited;
172   }
173
174   bool is_mounted()
175   {
176     return mounted;
177   }
178
179   int conf_read_file(const char *path_list)
180   {
181     int ret = cct->_conf->parse_config_files(path_list, NULL, 0);
182     if (ret)
183       return ret;
184     cct->_conf->apply_changes(NULL);
185     cct->_conf->complain_about_parse_errors(cct);
186     return 0;
187   }
188
189   int conf_parse_argv(int argc, const char **argv)
190   {
191     int ret;
192     vector<const char*> args;
193     argv_to_vec(argc, argv, args);
194     ret = cct->_conf->parse_argv(args);
195     if (ret)
196         return ret;
197     cct->_conf->apply_changes(NULL);
198     return 0;
199   }
200
201   int conf_parse_env(const char *name)
202   {
203     md_config_t *conf = cct->_conf;
204     vector<const char*> args;
205     env_to_vec(args, name);
206     int ret = conf->parse_argv(args);
207     if (ret)
208       return ret;
209     conf->apply_changes(NULL);
210     return 0;
211   }
212
213   int conf_set(const char *option, const char *value)
214   {
215     int ret = cct->_conf->set_val(option, value);
216     if (ret)
217       return ret;
218     cct->_conf->apply_changes(NULL);
219     return 0;
220   }
221
222   int conf_get(const char *option, char *buf, size_t len)
223   {
224     char *tmp = buf;
225     return cct->_conf->get_val(option, &tmp, len);
226   }
227
228   Client *get_client()
229   {
230     return client;
231   }
232
233   const char *get_cwd(const UserPerm& perms)
234   {
235     client->getcwd(cwd, perms);
236     return cwd.c_str();
237   }
238
239   int chdir(const char *to, const UserPerm& perms)
240   {
241     return client->chdir(to, cwd, perms);
242   }
243
244   CephContext *get_ceph_context() const {
245     return cct;
246   }
247
248   UserPerm default_perms;
249 private:
250   bool mounted;
251   bool inited;
252   StandaloneClient *client;
253   MonClient *monclient;
254   Messenger *messenger;
255   CephContext *cct;
256   std::string cwd;
257 };
258
259 static void do_out_buffer(bufferlist& outbl, char **outbuf, size_t *outbuflen)
260 {
261   if (outbuf) {
262     if (outbl.length() > 0) {
263       *outbuf = (char *)malloc(outbl.length());
264       memcpy(*outbuf, outbl.c_str(), outbl.length());
265     } else {
266       *outbuf = NULL;
267     }
268   }
269   if (outbuflen)
270     *outbuflen = outbl.length();
271 }
272
273 static void do_out_buffer(string& outbl, char **outbuf, size_t *outbuflen)
274 {
275   if (outbuf) {
276     if (outbl.length() > 0) {
277       *outbuf = (char *)malloc(outbl.length());
278       memcpy(*outbuf, outbl.c_str(), outbl.length());
279     } else {
280       *outbuf = NULL;
281     }
282   }
283   if (outbuflen)
284     *outbuflen = outbl.length();
285 }
286
287 extern "C" UserPerm *ceph_userperm_new(uid_t uid, gid_t gid, int ngids,
288                                        gid_t *gidlist)
289 {
290   return new (std::nothrow) UserPerm(uid, gid, ngids, gidlist);
291 }
292
293 extern "C" void ceph_userperm_destroy(UserPerm *perm)
294 {
295   delete perm;
296 }
297
298 extern "C" const char *ceph_version(int *pmajor, int *pminor, int *ppatch)
299 {
300   int major, minor, patch;
301   const char *v = ceph_version_to_str();
302
303   int n = sscanf(v, "%d.%d.%d", &major, &minor, &patch);
304   if (pmajor)
305     *pmajor = (n >= 1) ? major : 0;
306   if (pminor)
307     *pminor = (n >= 2) ? minor : 0;
308   if (ppatch)
309     *ppatch = (n >= 3) ? patch : 0;
310   return VERSION;
311 }
312
313 extern "C" int ceph_create_with_context(struct ceph_mount_info **cmount, CephContext *cct)
314 {
315   *cmount = new struct ceph_mount_info(cct);
316   return 0;
317 }
318
319 extern "C" int ceph_create_from_rados(struct ceph_mount_info **cmount,
320     rados_t cluster)
321 {
322   auto rados = (librados::RadosClient *) cluster;
323   auto cct = rados->cct;
324   return ceph_create_with_context(cmount, cct);
325 }
326
327 extern "C" int ceph_create(struct ceph_mount_info **cmount, const char * const id)
328 {
329   CephInitParameters iparams(CEPH_ENTITY_TYPE_CLIENT);
330   if (id) {
331     iparams.name.set(CEPH_ENTITY_TYPE_CLIENT, id);
332   }
333
334   CephContext *cct = common_preinit(iparams, CODE_ENVIRONMENT_LIBRARY, 0);
335   cct->_conf->parse_env(); // environment variables coverride
336   cct->_conf->apply_changes(NULL);
337   int ret = ceph_create_with_context(cmount, cct);
338   cct->put();
339   return ret;
340 }
341
342 extern "C" int ceph_unmount(struct ceph_mount_info *cmount)
343 {
344   return cmount->unmount();
345 }
346
347 extern "C" int ceph_release(struct ceph_mount_info *cmount)
348 {
349   if (cmount->is_mounted())
350     return -EISCONN;
351   delete cmount;
352   return 0;
353 }
354
355 extern "C" void ceph_shutdown(struct ceph_mount_info *cmount)
356 {
357   cmount->shutdown();
358   delete cmount;
359 }
360
361 extern "C" int ceph_conf_read_file(struct ceph_mount_info *cmount, const char *path)
362 {
363   return cmount->conf_read_file(path);
364 }
365
366 extern "C" int ceph_conf_parse_argv(struct ceph_mount_info *cmount, int argc,
367                                      const char **argv)
368 {
369   return cmount->conf_parse_argv(argc, argv);
370 }
371
372 extern "C" int ceph_conf_parse_env(struct ceph_mount_info *cmount, const char *name)
373 {
374   return cmount->conf_parse_env(name);
375 }
376
377 extern "C" int ceph_conf_set(struct ceph_mount_info *cmount, const char *option,
378                              const char *value)
379 {
380   return cmount->conf_set(option, value);
381 }
382
383 extern "C" int ceph_conf_get(struct ceph_mount_info *cmount, const char *option,
384                              char *buf, size_t len)
385 {
386   if (buf == NULL) {
387     return -EINVAL;
388   }
389   return cmount->conf_get(option, buf, len);
390 }
391
392 extern "C" int ceph_mds_command(struct ceph_mount_info *cmount,
393     const char *mds_spec,
394     const char **cmd,
395     size_t cmdlen,
396     const char *inbuf, size_t inbuflen,
397     char **outbuf, size_t *outbuflen,
398     char **outsbuf, size_t *outsbuflen)
399 {
400   bufferlist inbl;
401   bufferlist outbl;
402   std::vector<string> cmdv;
403   std::string outs;
404
405   if (!cmount->is_initialized()) {
406     return -ENOTCONN;
407   }
408
409   // Construct inputs
410   for (size_t i = 0; i < cmdlen; ++i) {
411     cmdv.push_back(cmd[i]);
412   }
413   inbl.append(inbuf, inbuflen);
414
415   // Issue remote command
416   C_SaferCond cond;
417   int r = cmount->get_client()->mds_command(
418       mds_spec,
419       cmdv, inbl,
420       &outbl, &outs,
421       &cond);
422
423   if (r != 0) {
424     goto out;
425   }
426
427   // Wait for completion
428   r = cond.wait();
429
430   // Construct outputs
431   do_out_buffer(outbl, outbuf, outbuflen);
432   do_out_buffer(outs, outsbuf, outsbuflen);
433
434 out:
435   return r;
436 }
437
438 extern "C" int ceph_init(struct ceph_mount_info *cmount)
439 {
440   return cmount->init();
441 }
442
443 extern "C" int ceph_mount(struct ceph_mount_info *cmount, const char *root)
444 {
445   std::string mount_root;
446   if (root)
447     mount_root = root;
448   return cmount->mount(mount_root, cmount->default_perms);
449 }
450
451 extern "C" int ceph_is_mounted(struct ceph_mount_info *cmount)
452 {
453   return cmount->is_mounted() ? 1 : 0;
454 }
455
456 extern "C" struct UserPerm *ceph_mount_perms(struct ceph_mount_info *cmount)
457 {
458   return &cmount->default_perms;
459 }
460
461 extern "C" int ceph_statfs(struct ceph_mount_info *cmount, const char *path,
462                            struct statvfs *stbuf)
463 {
464   if (!cmount->is_mounted())
465     return -ENOTCONN;
466   return cmount->get_client()->statfs(path, stbuf, cmount->default_perms);
467 }
468
469 extern "C" int ceph_get_local_osd(struct ceph_mount_info *cmount)
470 {
471   if (!cmount->is_mounted())
472     return -ENOTCONN;
473   return cmount->get_client()->get_local_osd();
474 }
475
476 extern "C" const char* ceph_getcwd(struct ceph_mount_info *cmount)
477 {
478   return cmount->get_cwd(cmount->default_perms);
479 }
480
481 extern "C" int ceph_chdir (struct ceph_mount_info *cmount, const char *s)
482 {
483   if (!cmount->is_mounted())
484     return -ENOTCONN;
485   return cmount->chdir(s, cmount->default_perms);
486 }
487
488 extern "C" int ceph_opendir(struct ceph_mount_info *cmount,
489                             const char *name, struct ceph_dir_result **dirpp)
490 {
491   if (!cmount->is_mounted())
492     return -ENOTCONN;
493   return cmount->get_client()->opendir(name, (dir_result_t **)dirpp, cmount->default_perms);
494 }
495
496 extern "C" int ceph_closedir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
497 {
498   if (!cmount->is_mounted())
499     return -ENOTCONN;
500   return cmount->get_client()->closedir(reinterpret_cast<dir_result_t*>(dirp));
501 }
502
503 extern "C" struct dirent * ceph_readdir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
504 {
505   if (!cmount->is_mounted()) {
506     /* Client::readdir also sets errno to signal errors. */
507     errno = ENOTCONN;
508     return NULL;
509   }
510   return cmount->get_client()->readdir(reinterpret_cast<dir_result_t*>(dirp));
511 }
512
513 extern "C" int ceph_readdir_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, struct dirent *de)
514 {
515   if (!cmount->is_mounted())
516     return -ENOTCONN;
517   return cmount->get_client()->readdir_r(reinterpret_cast<dir_result_t*>(dirp), de);
518 }
519
520 extern "C" int ceph_readdirplus_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp,
521                                   struct dirent *de, struct ceph_statx *stx, unsigned want,
522                                   unsigned flags, struct Inode **out)
523 {
524   if (!cmount->is_mounted())
525     return -ENOTCONN;
526   if (flags & ~CEPH_REQ_FLAG_MASK)
527     return -EINVAL;
528   return cmount->get_client()->readdirplus_r(reinterpret_cast<dir_result_t*>(dirp), de, stx, want, flags, out);
529 }
530
531 extern "C" int ceph_getdents(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp,
532                              char *buf, int buflen)
533 {
534   if (!cmount->is_mounted())
535     return -ENOTCONN;
536   return cmount->get_client()->getdents(reinterpret_cast<dir_result_t*>(dirp), buf, buflen);
537 }
538
539 extern "C" int ceph_getdnames(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp,
540                               char *buf, int buflen)
541 {
542   if (!cmount->is_mounted())
543     return -ENOTCONN;
544   return cmount->get_client()->getdnames(reinterpret_cast<dir_result_t*>(dirp), buf, buflen);
545 }
546
547 extern "C" void ceph_rewinddir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
548 {
549   if (!cmount->is_mounted())
550     return;
551   cmount->get_client()->rewinddir(reinterpret_cast<dir_result_t*>(dirp));
552 }
553
554 extern "C" int64_t ceph_telldir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp)
555 {
556   if (!cmount->is_mounted())
557     return -ENOTCONN;
558   return cmount->get_client()->telldir(reinterpret_cast<dir_result_t*>(dirp));
559 }
560
561 extern "C" void ceph_seekdir(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, int64_t offset)
562 {
563   if (!cmount->is_mounted())
564     return;
565   cmount->get_client()->seekdir(reinterpret_cast<dir_result_t*>(dirp), offset);
566 }
567
568 extern "C" int ceph_link (struct ceph_mount_info *cmount, const char *existing,
569                           const char *newname)
570 {
571   if (!cmount->is_mounted())
572     return -ENOTCONN;
573   return cmount->get_client()->link(existing, newname, cmount->default_perms);
574 }
575
576 extern "C" int ceph_unlink(struct ceph_mount_info *cmount, const char *path)
577 {
578   if (!cmount->is_mounted())
579     return -ENOTCONN;
580   return cmount->get_client()->unlink(path, cmount->default_perms);
581 }
582
583 extern "C" int ceph_rename(struct ceph_mount_info *cmount, const char *from,
584                            const char *to)
585 {
586   if (!cmount->is_mounted())
587     return -ENOTCONN;
588   return cmount->get_client()->rename(from, to, cmount->default_perms);
589 }
590
591 // dirs
592 extern "C" int ceph_mkdir(struct ceph_mount_info *cmount, const char *path, mode_t mode)
593 {
594   if (!cmount->is_mounted())
595     return -ENOTCONN;
596   return cmount->get_client()->mkdir(path, mode, cmount->default_perms);
597 }
598
599 extern "C" int ceph_mkdirs(struct ceph_mount_info *cmount, const char *path, mode_t mode)
600 {
601   if (!cmount->is_mounted())
602     return -ENOTCONN;
603   return cmount->get_client()->mkdirs(path, mode, cmount->default_perms);
604 }
605
606 extern "C" int ceph_rmdir(struct ceph_mount_info *cmount, const char *path)
607 {
608   if (!cmount->is_mounted())
609     return -ENOTCONN;
610   return cmount->get_client()->rmdir(path, cmount->default_perms);
611 }
612
613 // symlinks
614 extern "C" int ceph_readlink(struct ceph_mount_info *cmount, const char *path,
615                              char *buf, int64_t size)
616 {
617   if (!cmount->is_mounted())
618     return -ENOTCONN;
619   return cmount->get_client()->readlink(path, buf, size, cmount->default_perms);
620 }
621
622 extern "C" int ceph_symlink(struct ceph_mount_info *cmount, const char *existing,
623                             const char *newname)
624 {
625   if (!cmount->is_mounted())
626     return -ENOTCONN;
627   return cmount->get_client()->symlink(existing, newname, cmount->default_perms);
628 }
629
630 extern "C" int ceph_fstatx(struct ceph_mount_info *cmount, int fd, struct ceph_statx *stx,
631                             unsigned int want, unsigned int flags)
632 {
633   if (!cmount->is_mounted())
634     return -ENOTCONN;
635   if (flags & ~CEPH_REQ_FLAG_MASK)
636     return -EINVAL;
637   return cmount->get_client()->fstatx(fd, stx, cmount->default_perms,
638                                       want, flags);
639 }
640
641 extern "C" int ceph_statx(struct ceph_mount_info *cmount, const char *path,
642                           struct ceph_statx *stx, unsigned int want, unsigned int flags)
643 {
644   if (!cmount->is_mounted())
645     return -ENOTCONN;
646   if (flags & ~CEPH_REQ_FLAG_MASK)
647     return -EINVAL;
648   return cmount->get_client()->statx(path, stx, cmount->default_perms,
649                                      want, flags);
650 }
651
652 extern "C" int ceph_fsetattrx(struct ceph_mount_info *cmount, int fd,
653                               struct ceph_statx *stx, int mask)
654 {
655   if (!cmount->is_mounted())
656     return -ENOTCONN;
657   return cmount->get_client()->fsetattrx(fd, stx, mask, cmount->default_perms);
658 }
659
660 extern "C" int ceph_setattrx(struct ceph_mount_info *cmount, const char *relpath,
661                             struct ceph_statx *stx, int mask, int flags)
662 {
663   if (!cmount->is_mounted())
664     return -ENOTCONN;
665   if (flags & ~CEPH_REQ_FLAG_MASK)
666     return -EINVAL;
667   return cmount->get_client()->setattrx(relpath, stx, mask,
668                                         cmount->default_perms, flags);
669 }
670
671 // *xattr() calls supporting samba/vfs
672 extern "C" int ceph_getxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size)
673 {
674   if (!cmount->is_mounted())
675     return -ENOTCONN;
676
677   return cmount->get_client()->getxattr(path, name, value, size, cmount->default_perms);
678 }
679
680 extern "C" int ceph_lgetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, void *value, size_t size)
681 {
682   if (!cmount->is_mounted())
683     return -ENOTCONN;
684   return cmount->get_client()->lgetxattr(path, name, value, size, cmount->default_perms);
685 }
686
687 extern "C" int ceph_fgetxattr(struct ceph_mount_info *cmount, int fd, const char *name, void *value, size_t size)
688 {
689   if (!cmount->is_mounted())
690     return -ENOTCONN;
691   return cmount->get_client()->fgetxattr(fd, name, value, size, cmount->default_perms);
692 }
693
694
695 extern "C" int ceph_listxattr(struct ceph_mount_info *cmount, const char *path, char *list, size_t size)
696 {
697   if (!cmount->is_mounted())
698     return -ENOTCONN;
699   return cmount->get_client()->listxattr(path, list, size, cmount->default_perms);
700 }
701
702 extern "C" int ceph_llistxattr(struct ceph_mount_info *cmount, const char *path, char *list, size_t size)
703 {
704   if (!cmount->is_mounted())
705     return -ENOTCONN;
706   return cmount->get_client()->llistxattr(path, list, size, cmount->default_perms);
707 }
708
709 extern "C" int ceph_flistxattr(struct ceph_mount_info *cmount, int fd, char *list, size_t size)
710 {
711   if (!cmount->is_mounted())
712     return -ENOTCONN;
713   return cmount->get_client()->flistxattr(fd, list, size, cmount->default_perms);
714 }
715
716 extern "C" int ceph_removexattr(struct ceph_mount_info *cmount, const char *path, const char *name)
717 {
718   if (!cmount->is_mounted())
719     return -ENOTCONN;
720   return cmount->get_client()->removexattr(path, name, cmount->default_perms);
721 }
722
723 extern "C" int ceph_lremovexattr(struct ceph_mount_info *cmount, const char *path, const char *name)
724 {
725   if (!cmount->is_mounted())
726     return -ENOTCONN;
727   return cmount->get_client()->lremovexattr(path, name, cmount->default_perms);
728 }
729
730 extern "C" int ceph_fremovexattr(struct ceph_mount_info *cmount, int fd, const char *name)
731 {
732   if (!cmount->is_mounted())
733     return -ENOTCONN;
734   return cmount->get_client()->fremovexattr(fd, name, cmount->default_perms);
735 }
736
737 extern "C" int ceph_setxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags)
738 {
739   if (!cmount->is_mounted())
740     return -ENOTCONN;
741   return cmount->get_client()->setxattr(path, name, value, size, flags, cmount->default_perms);
742 }
743
744 extern "C" int ceph_lsetxattr(struct ceph_mount_info *cmount, const char *path, const char *name, const void *value, size_t size, int flags)
745 {
746   if (!cmount->is_mounted())
747     return -ENOTCONN;
748   return cmount->get_client()->lsetxattr(path, name, value, size, flags, cmount->default_perms);
749 }
750
751 extern "C" int ceph_fsetxattr(struct ceph_mount_info *cmount, int fd, const char *name, const void *value, size_t size, int flags)
752 {
753   if (!cmount->is_mounted())
754     return -ENOTCONN;
755   return cmount->get_client()->fsetxattr(fd, name, value, size, flags, cmount->default_perms);
756 }
757 /* end xattr support */
758
759 extern "C" int ceph_chmod(struct ceph_mount_info *cmount, const char *path, mode_t mode)
760 {
761   if (!cmount->is_mounted())
762     return -ENOTCONN;
763   return cmount->get_client()->chmod(path, mode, cmount->default_perms);
764 }
765 extern "C" int ceph_fchmod(struct ceph_mount_info *cmount, int fd, mode_t mode)
766 {
767   if (!cmount->is_mounted())
768     return -ENOTCONN;
769   return cmount->get_client()->fchmod(fd, mode, cmount->default_perms);
770 }
771 extern "C" int ceph_chown(struct ceph_mount_info *cmount, const char *path,
772                           int uid, int gid)
773 {
774   if (!cmount->is_mounted())
775     return -ENOTCONN;
776   return cmount->get_client()->chown(path, uid, gid, cmount->default_perms);
777 }
778 extern "C" int ceph_fchown(struct ceph_mount_info *cmount, int fd,
779                            int uid, int gid)
780 {
781   if (!cmount->is_mounted())
782     return -ENOTCONN;
783   return cmount->get_client()->fchown(fd, uid, gid, cmount->default_perms);
784 }
785 extern "C" int ceph_lchown(struct ceph_mount_info *cmount, const char *path,
786                            int uid, int gid)
787 {
788   if (!cmount->is_mounted())
789     return -ENOTCONN;
790   return cmount->get_client()->lchown(path, uid, gid, cmount->default_perms);
791 }
792
793
794 extern "C" int ceph_utime(struct ceph_mount_info *cmount, const char *path,
795                           struct utimbuf *buf)
796 {
797   if (!cmount->is_mounted())
798     return -ENOTCONN;
799   return cmount->get_client()->utime(path, buf, cmount->default_perms);
800 }
801
802 extern "C" int ceph_flock(struct ceph_mount_info *cmount, int fd, int operation,
803                           uint64_t owner)
804 {
805   if (!cmount->is_mounted())
806     return -ENOTCONN;
807   return cmount->get_client()->flock(fd, operation, owner);
808 }
809
810 extern "C" int ceph_truncate(struct ceph_mount_info *cmount, const char *path,
811                              int64_t size)
812 {
813   if (!cmount->is_mounted())
814     return -ENOTCONN;
815   return cmount->get_client()->truncate(path, size, cmount->default_perms);
816 }
817
818 // file ops
819 extern "C" int ceph_mknod(struct ceph_mount_info *cmount, const char *path,
820                           mode_t mode, dev_t rdev)
821 {
822   if (!cmount->is_mounted())
823     return -ENOTCONN;
824   return cmount->get_client()->mknod(path, mode, cmount->default_perms, rdev);
825 }
826
827 extern "C" int ceph_open(struct ceph_mount_info *cmount, const char *path,
828                          int flags, mode_t mode)
829 {
830   if (!cmount->is_mounted())
831     return -ENOTCONN;
832   return cmount->get_client()->open(path, flags, cmount->default_perms, mode);
833 }
834
835 extern "C" int ceph_open_layout(struct ceph_mount_info *cmount, const char *path, int flags,
836     mode_t mode, int stripe_unit, int stripe_count, int object_size, const char *data_pool)
837 {
838   if (!cmount->is_mounted())
839     return -ENOTCONN;
840   return cmount->get_client()->open(path, flags, cmount->default_perms, mode,
841                                     stripe_unit, stripe_count,
842                                     object_size, data_pool);
843 }
844
845 extern "C" int ceph_close(struct ceph_mount_info *cmount, int fd)
846 {
847   if (!cmount->is_mounted())
848     return -ENOTCONN;
849   return cmount->get_client()->close(fd);
850 }
851
852 extern "C" int64_t ceph_lseek(struct ceph_mount_info *cmount, int fd,
853                              int64_t offset, int whence)
854 {
855   if (!cmount->is_mounted())
856     return -ENOTCONN;
857   return cmount->get_client()->lseek(fd, offset, whence);
858 }
859
860 extern "C" int ceph_read(struct ceph_mount_info *cmount, int fd, char *buf,
861                          int64_t size, int64_t offset)
862 {
863   if (!cmount->is_mounted())
864     return -ENOTCONN;
865   return cmount->get_client()->read(fd, buf, size, offset);
866 }
867
868 extern "C" int ceph_preadv(struct ceph_mount_info *cmount, int fd,
869               const struct iovec *iov, int iovcnt, int64_t offset)
870 {
871   if (!cmount->is_mounted())
872       return -ENOTCONN;
873   return cmount->get_client()->preadv(fd, iov, iovcnt, offset);
874 }
875
876 extern "C" int ceph_write(struct ceph_mount_info *cmount, int fd, const char *buf,
877                           int64_t size, int64_t offset)
878 {
879   if (!cmount->is_mounted())
880     return -ENOTCONN;
881   return cmount->get_client()->write(fd, buf, size, offset);
882 }
883
884 extern "C" int ceph_pwritev(struct ceph_mount_info *cmount, int fd,
885               const struct iovec *iov, int iovcnt, int64_t offset)
886 {
887   if (!cmount->is_mounted())
888     return -ENOTCONN;
889   return cmount->get_client()->pwritev(fd, iov, iovcnt, offset);
890 }
891
892 extern "C" int ceph_ftruncate(struct ceph_mount_info *cmount, int fd, int64_t size)
893 {
894   if (!cmount->is_mounted())
895     return -ENOTCONN;
896   return cmount->get_client()->ftruncate(fd, size, cmount->default_perms);
897 }
898
899 extern "C" int ceph_fsync(struct ceph_mount_info *cmount, int fd, int syncdataonly)
900 {
901   if (!cmount->is_mounted())
902     return -ENOTCONN;
903   return cmount->get_client()->fsync(fd, syncdataonly);
904 }
905
906 extern "C" int ceph_fallocate(struct ceph_mount_info *cmount, int fd, int mode,
907                               int64_t offset, int64_t length)
908 {
909   if (!cmount->is_mounted())
910     return -ENOTCONN;
911   return cmount->get_client()->fallocate(fd, mode, offset, length);
912 }
913
914 extern "C" int ceph_sync_fs(struct ceph_mount_info *cmount)
915 {
916   if (!cmount->is_mounted())
917     return -ENOTCONN;
918   return cmount->get_client()->sync_fs();
919 }
920
921
922 extern "C" int ceph_get_file_stripe_unit(struct ceph_mount_info *cmount, int fh)
923 {
924   file_layout_t l;
925   int r;
926
927   if (!cmount->is_mounted())
928     return -ENOTCONN;
929   r = cmount->get_client()->fdescribe_layout(fh, &l);
930   if (r < 0)
931     return r;
932   return l.stripe_unit;
933 }
934
935 extern "C" int ceph_get_path_stripe_unit(struct ceph_mount_info *cmount, const char *path)
936 {
937   file_layout_t l;
938   int r;
939
940   if (!cmount->is_mounted())
941     return -ENOTCONN;
942   r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
943   if (r < 0)
944     return r;
945   return l.stripe_unit;
946 }
947
948 extern "C" int ceph_get_file_stripe_count(struct ceph_mount_info *cmount, int fh)
949 {
950   file_layout_t l;
951   int r;
952
953   if (!cmount->is_mounted())
954     return -ENOTCONN;
955   r = cmount->get_client()->fdescribe_layout(fh, &l);
956   if (r < 0)
957     return r;
958   return l.stripe_count;
959 }
960
961 extern "C" int ceph_get_path_stripe_count(struct ceph_mount_info *cmount, const char *path)
962 {
963   file_layout_t l;
964   int r;
965
966   if (!cmount->is_mounted())
967     return -ENOTCONN;
968   r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
969   if (r < 0)
970     return r;
971   return l.stripe_count;
972 }
973
974 extern "C" int ceph_get_file_object_size(struct ceph_mount_info *cmount, int fh)
975 {
976   file_layout_t l;
977   int r;
978
979   if (!cmount->is_mounted())
980     return -ENOTCONN;
981   r = cmount->get_client()->fdescribe_layout(fh, &l);
982   if (r < 0)
983     return r;
984   return l.object_size;
985 }
986
987 extern "C" int ceph_get_path_object_size(struct ceph_mount_info *cmount, const char *path)
988 {
989   file_layout_t l;
990   int r;
991
992   if (!cmount->is_mounted())
993     return -ENOTCONN;
994   r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
995   if (r < 0)
996     return r;
997   return l.object_size;
998 }
999
1000 extern "C" int ceph_get_file_pool(struct ceph_mount_info *cmount, int fh)
1001 {
1002   file_layout_t l;
1003   int r;
1004
1005   if (!cmount->is_mounted())
1006     return -ENOTCONN;
1007   r = cmount->get_client()->fdescribe_layout(fh, &l);
1008   if (r < 0)
1009     return r;
1010   return l.pool_id;
1011 }
1012
1013 extern "C" int ceph_get_path_pool(struct ceph_mount_info *cmount, const char *path)
1014 {
1015   file_layout_t l;
1016   int r;
1017
1018   if (!cmount->is_mounted())
1019     return -ENOTCONN;
1020   r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1021   if (r < 0)
1022     return r;
1023   return l.pool_id;
1024 }
1025
1026 extern "C" int ceph_get_file_pool_name(struct ceph_mount_info *cmount, int fh, char *buf, size_t len)
1027 {
1028   file_layout_t l;
1029   int r;
1030
1031   if (!cmount->is_mounted())
1032     return -ENOTCONN;
1033   r = cmount->get_client()->fdescribe_layout(fh, &l);
1034   if (r < 0)
1035     return r;
1036   string name = cmount->get_client()->get_pool_name(l.pool_id);
1037   if (len == 0)
1038     return name.length();
1039   if (name.length() > len)
1040     return -ERANGE;
1041   strncpy(buf, name.c_str(), len);
1042   return name.length();
1043 }
1044
1045 extern "C" int ceph_get_pool_name(struct ceph_mount_info *cmount, int pool, char *buf, size_t len)
1046 {
1047   if (!cmount->is_mounted())
1048     return -ENOTCONN;
1049   string name = cmount->get_client()->get_pool_name(pool);
1050   if (len == 0)
1051     return name.length();
1052   if (name.length() > len)
1053     return -ERANGE;
1054   strncpy(buf, name.c_str(), len);
1055   return name.length();
1056 }
1057
1058 extern "C" int ceph_get_path_pool_name(struct ceph_mount_info *cmount, const char *path, char *buf, size_t len)
1059 {
1060   file_layout_t l;
1061   int r;
1062
1063   if (!cmount->is_mounted())
1064     return -ENOTCONN;
1065   r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1066   if (r < 0)
1067     return r;
1068   string name = cmount->get_client()->get_pool_name(l.pool_id);
1069   if (len == 0)
1070     return name.length();
1071   if (name.length() > len)
1072     return -ERANGE;
1073   strncpy(buf, name.c_str(), len);
1074   return name.length();
1075 }
1076
1077 extern "C" int ceph_get_default_data_pool_name(struct ceph_mount_info *cmount, char *buf, size_t len)
1078 {
1079   if (!cmount->is_mounted())
1080     return -ENOTCONN;
1081   int64_t pool_id = cmount->get_client()->get_default_pool_id();
1082  
1083   string name = cmount->get_client()->get_pool_name(pool_id);
1084   if (len == 0)
1085     return name.length();
1086   if (name.length() > len)
1087     return -ERANGE;
1088   strncpy(buf, name.c_str(), len);
1089   return name.length(); 
1090 }
1091
1092 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)
1093 {
1094   file_layout_t l;
1095   int r;
1096
1097   if (!cmount->is_mounted())
1098     return -ENOTCONN;
1099   r = cmount->get_client()->fdescribe_layout(fh, &l);
1100   if (r < 0)
1101     return r;
1102   if (stripe_unit)
1103     *stripe_unit = l.stripe_unit;
1104   if (stripe_count)
1105     *stripe_count = l.stripe_count;
1106   if (object_size)
1107     *object_size = l.object_size;
1108   if (pg_pool)
1109     *pg_pool = l.pool_id;
1110   return 0;
1111 }
1112
1113 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)
1114 {
1115   file_layout_t l;
1116   int r;
1117
1118   if (!cmount->is_mounted())
1119     return -ENOTCONN;
1120   r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1121   if (r < 0)
1122     return r;
1123   if (stripe_unit)
1124     *stripe_unit = l.stripe_unit;
1125   if (stripe_count)
1126     *stripe_count = l.stripe_count;
1127   if (object_size)
1128     *object_size = l.object_size;
1129   if (pg_pool)
1130     *pg_pool = l.pool_id;
1131   return 0;
1132 }
1133
1134 extern "C" int ceph_get_file_replication(struct ceph_mount_info *cmount, int fh)
1135 {
1136   file_layout_t l;
1137   int r;
1138
1139   if (!cmount->is_mounted())
1140     return -ENOTCONN;
1141   r = cmount->get_client()->fdescribe_layout(fh, &l);
1142   if (r < 0)
1143     return r;
1144   int rep = cmount->get_client()->get_pool_replication(l.pool_id);
1145   return rep;
1146 }
1147
1148 extern "C" int ceph_get_path_replication(struct ceph_mount_info *cmount, const char *path)
1149 {
1150   file_layout_t l;
1151   int r;
1152
1153   if (!cmount->is_mounted())
1154     return -ENOTCONN;
1155   r = cmount->get_client()->describe_layout(path, &l, cmount->default_perms);
1156   if (r < 0)
1157     return r;
1158   int rep = cmount->get_client()->get_pool_replication(l.pool_id);
1159   return rep;
1160 }
1161
1162 extern "C" int ceph_set_default_file_stripe_unit(struct ceph_mount_info *cmount,
1163                                                  int stripe)
1164 {
1165   // this option no longer exists
1166   return -EOPNOTSUPP;
1167 }
1168
1169 extern "C" int ceph_set_default_file_stripe_count(struct ceph_mount_info *cmount,
1170                                                   int count)
1171 {
1172   // this option no longer exists
1173   return -EOPNOTSUPP;
1174 }
1175
1176 extern "C" int ceph_set_default_object_size(struct ceph_mount_info *cmount, int size)
1177 {
1178   // this option no longer exists
1179   return -EOPNOTSUPP;
1180 }
1181
1182 extern "C" int ceph_set_default_file_replication(struct ceph_mount_info *cmount,
1183                                                  int replication)
1184 {
1185   // this option no longer exists
1186   return -EOPNOTSUPP;
1187 }
1188
1189 extern "C" int ceph_set_default_preferred_pg(struct ceph_mount_info *cmount, int osd)
1190 {
1191   // this option no longer exists
1192   return -EOPNOTSUPP;
1193 }
1194
1195 extern "C" int ceph_get_file_extent_osds(struct ceph_mount_info *cmount, int fh,
1196     int64_t offset, int64_t *length, int *osds, int nosds)
1197 {
1198   if (nosds < 0)
1199     return -EINVAL;
1200
1201   if (!cmount->is_mounted())
1202     return -ENOTCONN;
1203
1204   vector<int> vosds;
1205   int ret = cmount->get_client()->get_file_extent_osds(fh, offset, length, vosds);
1206   if (ret < 0)
1207     return ret;
1208
1209   if (!nosds)
1210     return vosds.size();
1211
1212   if ((int)vosds.size() > nosds)
1213     return -ERANGE;
1214
1215   for (int i = 0; i < (int)vosds.size(); i++)
1216     osds[i] = vosds[i];
1217
1218   return vosds.size();
1219 }
1220
1221 extern "C" int ceph_get_osd_crush_location(struct ceph_mount_info *cmount,
1222     int osd, char *path, size_t len)
1223 {
1224   if (!cmount->is_mounted())
1225     return -ENOTCONN;
1226
1227   if (!path && len)
1228     return -EINVAL;
1229
1230   vector<pair<string, string> > loc;
1231   int ret = cmount->get_client()->get_osd_crush_location(osd, loc);
1232   if (ret)
1233     return ret;
1234
1235   size_t needed = 0;
1236   size_t cur = 0;
1237   vector<pair<string, string> >::iterator it;
1238   for (it = loc.begin(); it != loc.end(); ++it) {
1239     string& type = it->first;
1240     string& name = it->second;
1241     needed += type.size() + name.size() + 2;
1242     if (needed <= len) {
1243       if (path)
1244         strcpy(path + cur, type.c_str());
1245       cur += type.size() + 1;
1246       if (path)
1247         strcpy(path + cur, name.c_str());
1248       cur += name.size() + 1;
1249     }
1250   }
1251
1252   if (len == 0)
1253     return needed;
1254
1255   if (needed > len)
1256     return -ERANGE;
1257
1258   return needed;
1259 }
1260
1261 extern "C" int ceph_get_osd_addr(struct ceph_mount_info *cmount, int osd,
1262     struct sockaddr_storage *addr)
1263 {
1264   if (!cmount->is_mounted())
1265     return -ENOTCONN;
1266
1267   if (!addr)
1268     return -EINVAL;
1269
1270   entity_addr_t address;
1271   int ret = cmount->get_client()->get_osd_addr(osd, address);
1272   if (ret < 0)
1273     return ret;
1274
1275   *addr = address.get_sockaddr_storage();
1276
1277   return 0;
1278 }
1279
1280 extern "C" int ceph_get_file_stripe_address(struct ceph_mount_info *cmount, int fh,
1281                                             int64_t offset, struct sockaddr_storage *addr, int naddr)
1282 {
1283   vector<entity_addr_t> address;
1284   unsigned i;
1285   int r;
1286
1287   if (naddr < 0)
1288     return -EINVAL;
1289
1290   if (!cmount->is_mounted())
1291     return -ENOTCONN;
1292
1293   r = cmount->get_client()->get_file_stripe_address(fh, offset, address);
1294   if (r < 0)
1295     return r;
1296
1297   for (i = 0; i < (unsigned)naddr && i < address.size(); i++)
1298     addr[i] = address[i].get_sockaddr_storage();
1299
1300   /* naddr == 0: drop through and return actual size */
1301   if (naddr && (address.size() > (unsigned)naddr))
1302     return -ERANGE;
1303
1304   return address.size();
1305 }
1306
1307 extern "C" int ceph_localize_reads(struct ceph_mount_info *cmount, int val)
1308 {
1309   if (!cmount->is_mounted())
1310     return -ENOTCONN;
1311   if (!val)
1312     cmount->get_client()->clear_filer_flags(CEPH_OSD_FLAG_LOCALIZE_READS);
1313   else
1314     cmount->get_client()->set_filer_flags(CEPH_OSD_FLAG_LOCALIZE_READS);
1315   return 0;
1316 }
1317
1318 extern "C" CephContext *ceph_get_mount_context(struct ceph_mount_info *cmount)
1319 {
1320   return cmount->get_ceph_context();
1321 }
1322
1323 extern "C" int ceph_debug_get_fd_caps(struct ceph_mount_info *cmount, int fd)
1324 {
1325   if (!cmount->is_mounted())
1326     return -ENOTCONN;
1327   return cmount->get_client()->get_caps_issued(fd);
1328 }
1329
1330 extern "C" int ceph_debug_get_file_caps(struct ceph_mount_info *cmount, const char *path)
1331 {
1332   if (!cmount->is_mounted())
1333     return -ENOTCONN;
1334   return cmount->get_client()->get_caps_issued(path, cmount->default_perms);
1335 }
1336
1337 extern "C" int ceph_get_stripe_unit_granularity(struct ceph_mount_info *cmount)
1338 {
1339   if (!cmount->is_mounted())
1340     return -ENOTCONN;
1341   return CEPH_MIN_STRIPE_UNIT;
1342 }
1343
1344 extern "C" int ceph_get_pool_id(struct ceph_mount_info *cmount, const char *pool_name)
1345 {
1346   if (!cmount->is_mounted())
1347     return -ENOTCONN;
1348
1349   if (!pool_name || !pool_name[0])
1350     return -EINVAL;
1351
1352   /* negative range reserved for errors */
1353   int64_t pool_id = cmount->get_client()->get_pool_id(pool_name);
1354   if (pool_id > 0x7fffffff)
1355     return -ERANGE;
1356
1357   /* get_pool_id error codes fit in int */
1358   return (int)pool_id;
1359 }
1360
1361 extern "C" int ceph_get_pool_replication(struct ceph_mount_info *cmount,
1362                                          int pool_id)
1363 {
1364   if (!cmount->is_mounted())
1365     return -ENOTCONN;
1366   return cmount->get_client()->get_pool_replication(pool_id);
1367 }
1368 /* Low-level exports */
1369
1370 extern "C" int ceph_ll_lookup_root(struct ceph_mount_info *cmount,
1371                   Inode **parent)
1372 {
1373   *parent = cmount->get_client()->get_root();
1374   if (*parent)
1375     return 0;
1376   return -EFAULT;
1377 }
1378
1379 extern "C" struct Inode *ceph_ll_get_inode(class ceph_mount_info *cmount,
1380                                            vinodeno_t vino)
1381 {
1382   return (cmount->get_client())->ll_get_inode(vino);
1383 }
1384
1385
1386 /**
1387  * Populates the client cache with the requested inode, and its
1388  * parent dentry.
1389  */
1390 extern "C" int ceph_ll_lookup_inode(
1391     struct ceph_mount_info *cmount,
1392     struct inodeno_t ino,
1393     Inode **inode)
1394 {
1395   int r = (cmount->get_client())->lookup_ino(ino, cmount->default_perms, inode);
1396   if (r) {
1397     return r;
1398   }
1399
1400   assert(inode != NULL);
1401   assert(*inode != NULL);
1402
1403   // Request the parent inode, so that we can look up the name
1404   Inode *parent;
1405   r = (cmount->get_client())->lookup_parent(*inode, cmount->default_perms, &parent);
1406   if (r && r != -EINVAL) {
1407     // Unexpected error
1408     (cmount->get_client())->ll_forget(*inode, 1);
1409     return r;
1410   } else if (r == -EINVAL) {
1411     // EINVAL indicates node without parents (root), drop out now
1412     // and don't try to look up the non-existent dentry.
1413     return 0;
1414   }
1415   // FIXME: I don't think this works; lookup_parent() returns 0 if the parent
1416   // is already in cache
1417   assert(parent != NULL);
1418
1419   // Finally, get the name (dentry) of the requested inode
1420   r = (cmount->get_client())->lookup_name(*inode, parent, cmount->default_perms);
1421   if (r) {
1422     // Unexpected error
1423     (cmount->get_client())->ll_forget(parent, 1);
1424     (cmount->get_client())->ll_forget(*inode, 1);
1425     return r;
1426   }
1427
1428   (cmount->get_client())->ll_forget(parent, 1);
1429   return 0;
1430 }
1431
1432 extern "C" int ceph_ll_lookup(struct ceph_mount_info *cmount,
1433                               Inode *parent, const char *name, Inode **out,
1434                               struct ceph_statx *stx, unsigned want,
1435                               unsigned flags, const UserPerm *perms)
1436 {
1437   if (flags & ~CEPH_REQ_FLAG_MASK)
1438     return -EINVAL;
1439   return (cmount->get_client())->ll_lookupx(parent, name, out, stx, want,
1440                                             flags, *perms);
1441 }
1442
1443 extern "C" int ceph_ll_put(class ceph_mount_info *cmount, Inode *in)
1444 {
1445   return (cmount->get_client()->ll_put(in));
1446 }
1447
1448 extern "C" int ceph_ll_forget(class ceph_mount_info *cmount, Inode *in,
1449                               int count)
1450 {
1451   return (cmount->get_client()->ll_forget(in, count));
1452 }
1453
1454 extern "C" int ceph_ll_walk(struct ceph_mount_info *cmount, const char* name, Inode **i,
1455                  struct ceph_statx *stx, unsigned int want, unsigned int flags,
1456                  const UserPerm *perms)
1457 {
1458   if (flags & ~CEPH_REQ_FLAG_MASK)
1459     return -EINVAL;
1460   return(cmount->get_client()->ll_walk(name, i, stx, want, flags, *perms));
1461 }
1462
1463 extern "C" int ceph_ll_getattr(class ceph_mount_info *cmount,
1464                                Inode *in, struct ceph_statx *stx,
1465                                unsigned int want, unsigned int flags,
1466                                const UserPerm *perms)
1467 {
1468   if (flags & ~CEPH_REQ_FLAG_MASK)
1469     return -EINVAL;
1470   return (cmount->get_client()->ll_getattrx(in, stx, want, flags, *perms));
1471 }
1472
1473 extern "C" int ceph_ll_setattr(class ceph_mount_info *cmount,
1474                                Inode *in, struct ceph_statx *stx,
1475                                int mask, const UserPerm *perms)
1476 {
1477   return (cmount->get_client()->ll_setattrx(in, stx, mask, *perms));
1478 }
1479
1480 extern "C" int ceph_ll_open(class ceph_mount_info *cmount, Inode *in,
1481                             int flags, Fh **fh, const UserPerm *perms)
1482 {
1483   return (cmount->get_client()->ll_open(in, flags, fh, *perms));
1484 }
1485
1486 extern "C" int ceph_ll_read(class ceph_mount_info *cmount, Fh* filehandle,
1487                             int64_t off, uint64_t len, char* buf)
1488 {
1489   bufferlist bl;
1490   int r = 0;
1491
1492   r = cmount->get_client()->ll_read(filehandle, off, len, &bl);
1493   if (r >= 0)
1494     {
1495       bl.copy(0, bl.length(), buf);
1496       r = bl.length();
1497     }
1498   return r;
1499 }
1500
1501 extern "C" int ceph_ll_read_block(class ceph_mount_info *cmount,
1502                                   Inode *in, uint64_t blockid,
1503                                   char* buf, uint64_t offset,
1504                                   uint64_t length,
1505                                   struct ceph_file_layout* layout)
1506 {
1507   file_layout_t l;
1508   int r = (cmount->get_client()->ll_read_block(in, blockid, buf, offset,
1509                                                length, &l));
1510   l.to_legacy(layout);
1511   return r;
1512 }
1513
1514 extern "C" int ceph_ll_write_block(class ceph_mount_info *cmount,
1515                                    Inode *in, uint64_t blockid,
1516                                    char *buf, uint64_t offset,
1517                                    uint64_t length,
1518                                    struct ceph_file_layout *layout,
1519                                    uint64_t snapseq, uint32_t sync)
1520 {
1521   file_layout_t l;
1522   int r = (cmount->get_client()->ll_write_block(in, blockid, buf, offset,
1523                                                 length, &l, snapseq, sync));
1524   l.to_legacy(layout);
1525   return r;
1526 }
1527
1528 extern "C" int ceph_ll_commit_blocks(class ceph_mount_info *cmount,
1529                                      Inode *in, uint64_t offset,
1530                                      uint64_t range)
1531 {
1532   return (cmount->get_client()->ll_commit_blocks(in, offset, range));
1533 }
1534
1535 extern "C" int ceph_ll_fsync(class ceph_mount_info *cmount,
1536                              Fh *fh, int syncdataonly)
1537 {
1538   return (cmount->get_client()->ll_fsync(fh, syncdataonly));
1539 }
1540
1541 extern "C" off_t ceph_ll_lseek(class ceph_mount_info *cmount,
1542                                 Fh *fh, off_t offset, int whence)
1543 {
1544   return (cmount->get_client()->ll_lseek(fh, offset, whence));
1545 }
1546
1547 extern "C" int ceph_ll_write(class ceph_mount_info *cmount,
1548                              Fh *fh, int64_t off, uint64_t len,
1549                              const char *data)
1550 {
1551   return (cmount->get_client()->ll_write(fh, off, len, data));
1552 }
1553
1554 extern "C" int64_t ceph_ll_readv(class ceph_mount_info *cmount,
1555                                  struct Fh *fh, const struct iovec *iov,
1556                                  int iovcnt, int64_t off)
1557 {
1558   return -1; // TODO:  implement
1559 }
1560
1561 extern "C" int64_t ceph_ll_writev(class ceph_mount_info *cmount,
1562                                   struct Fh *fh, const struct iovec *iov,
1563                                   int iovcnt, int64_t off)
1564 {
1565   return -1; // TODO:  implement
1566 }
1567
1568 extern "C" int ceph_ll_close(class ceph_mount_info *cmount, Fh* fh)
1569 {
1570   return (cmount->get_client()->ll_release(fh));
1571 }
1572
1573 extern "C" int ceph_ll_create(class ceph_mount_info *cmount,
1574                               Inode *parent, const char *name, mode_t mode,
1575                               int oflags, Inode **outp, Fh **fhp,
1576                               struct ceph_statx *stx, unsigned want,
1577                               unsigned lflags, const UserPerm *perms)
1578 {
1579   if (lflags & ~CEPH_REQ_FLAG_MASK)
1580     return -EINVAL;
1581   return (cmount->get_client())->ll_createx(parent, name, mode, oflags, outp,
1582                                             fhp, stx, want, lflags, *perms);
1583 }
1584
1585 extern "C" int ceph_ll_mknod(class ceph_mount_info *cmount, Inode *parent,
1586                              const char *name, mode_t mode, dev_t rdev,
1587                              Inode **out, struct ceph_statx *stx,
1588                              unsigned want, unsigned flags,
1589                              const UserPerm *perms)
1590 {
1591   if (flags & ~CEPH_REQ_FLAG_MASK)
1592     return -EINVAL;
1593   return (cmount->get_client())->ll_mknodx(parent, name, mode, rdev,
1594                                            out, stx, want, flags, *perms);
1595 }
1596
1597 extern "C" int ceph_ll_mkdir(class ceph_mount_info *cmount, Inode *parent,
1598                              const char *name, mode_t mode, Inode **out,
1599                              struct ceph_statx *stx, unsigned want,
1600                              unsigned flags, const UserPerm *perms)
1601 {
1602   if (flags & ~CEPH_REQ_FLAG_MASK)
1603     return -EINVAL;
1604   return cmount->get_client()->ll_mkdirx(parent, name, mode, out, stx, want,
1605                                          flags, *perms);
1606 }
1607
1608 extern "C" int ceph_ll_link(class ceph_mount_info *cmount,
1609                             Inode *in, Inode *newparent,
1610                             const char *name, const UserPerm *perms)
1611 {
1612   return cmount->get_client()->ll_link(in, newparent, name, *perms);
1613 }
1614
1615 extern "C" int ceph_ll_opendir(class ceph_mount_info *cmount,
1616                                Inode *in,
1617                                struct ceph_dir_result **dirpp,
1618                                const UserPerm *perms)
1619 {
1620   return (cmount->get_client()->ll_opendir(in, O_RDONLY, (dir_result_t**) dirpp,
1621                                            *perms));
1622 }
1623
1624 extern "C" int ceph_ll_releasedir(class ceph_mount_info *cmount,
1625                                   ceph_dir_result *dir)
1626 {
1627   (void) cmount->get_client()->ll_releasedir(reinterpret_cast<dir_result_t*>(dir));
1628   return (0);
1629 }
1630
1631 extern "C" int ceph_ll_rename(class ceph_mount_info *cmount,
1632                               Inode *parent, const char *name,
1633                               Inode *newparent, const char *newname,
1634                               const UserPerm *perms)
1635 {
1636   return cmount->get_client()->ll_rename(parent, name, newparent,
1637                                          newname, *perms);
1638 }
1639
1640 extern "C" int ceph_ll_unlink(class ceph_mount_info *cmount, Inode *in,
1641                               const char *name, const UserPerm *perms)
1642 {
1643   return cmount->get_client()->ll_unlink(in, name, *perms);
1644 }
1645
1646 extern "C" int ceph_ll_statfs(class ceph_mount_info *cmount,
1647                               Inode *in, struct statvfs *stbuf)
1648 {
1649   return (cmount->get_client()->ll_statfs(in, stbuf, cmount->default_perms));
1650 }
1651
1652 extern "C" int ceph_ll_readlink(class ceph_mount_info *cmount, Inode *in,
1653                                 char *buf, size_t bufsiz,
1654                                 const UserPerm *perms)
1655 {
1656   return cmount->get_client()->ll_readlink(in, buf, bufsiz, *perms);
1657 }
1658
1659 extern "C" int ceph_ll_symlink(class ceph_mount_info *cmount,
1660                                Inode *in, const char *name,
1661                                const char *value, Inode **out,
1662                                struct ceph_statx *stx, unsigned want,
1663                                unsigned flags, const UserPerm *perms)
1664 {
1665   if (flags & ~CEPH_REQ_FLAG_MASK)
1666     return -EINVAL;
1667   return (cmount->get_client()->ll_symlinkx(in, name, value, out, stx, want,
1668                                             flags, *perms));
1669 }
1670
1671 extern "C" int ceph_ll_rmdir(class ceph_mount_info *cmount,
1672                              Inode *in, const char *name,
1673                              const UserPerm *perms)
1674 {
1675   return cmount->get_client()->ll_rmdir(in, name, *perms);
1676 }
1677
1678 extern "C" int ceph_ll_getxattr(class ceph_mount_info *cmount,
1679                                 Inode *in, const char *name, void *value,
1680                                 size_t size, const UserPerm *perms)
1681 {
1682   return (cmount->get_client()->ll_getxattr(in, name, value, size, *perms));
1683 }
1684
1685 extern "C" int ceph_ll_listxattr(struct ceph_mount_info *cmount,
1686                               Inode *in, char *list,
1687                               size_t buf_size, size_t *list_size,
1688                               const UserPerm *perms)
1689 {
1690   int res = cmount->get_client()->ll_listxattr(in, list, buf_size, *perms);
1691   if (res >= 0) {
1692     *list_size = (size_t)res;
1693     return 0;
1694   }
1695   return res;
1696 }
1697
1698 extern "C" int ceph_ll_setxattr(class ceph_mount_info *cmount,
1699                                 Inode *in, const char *name,
1700                                 const void *value, size_t size,
1701                                 int flags, const UserPerm *perms)
1702 {
1703   return (cmount->get_client()->ll_setxattr(in, name, value, size, flags, *perms));
1704 }
1705
1706 extern "C" int ceph_ll_removexattr(class ceph_mount_info *cmount,
1707                                    Inode *in, const char *name,
1708                                    const UserPerm *perms)
1709 {
1710   return (cmount->get_client()->ll_removexattr(in, name, *perms));
1711 }
1712
1713 extern "C" int ceph_ll_getlk(struct ceph_mount_info *cmount,
1714                              Fh *fh, struct flock *fl, uint64_t owner)
1715 {
1716   return (cmount->get_client()->ll_getlk(fh, fl, owner));
1717 }
1718
1719 extern "C" int ceph_ll_setlk(struct ceph_mount_info *cmount,
1720                              Fh *fh, struct flock *fl, uint64_t owner,
1721                              int sleep)
1722 {
1723   return (cmount->get_client()->ll_setlk(fh, fl, owner, sleep));
1724 }
1725
1726 extern "C" uint32_t ceph_ll_stripe_unit(class ceph_mount_info *cmount,
1727                                         Inode *in)
1728 {
1729   return (cmount->get_client()->ll_stripe_unit(in));
1730 }
1731
1732 extern "C" uint32_t ceph_ll_file_layout(class ceph_mount_info *cmount,
1733                                         Inode *in,
1734                                         struct ceph_file_layout *layout)
1735 {
1736   file_layout_t l;
1737   int r = (cmount->get_client()->ll_file_layout(in, &l));
1738   l.to_legacy(layout);
1739   return r;
1740 }
1741
1742 uint64_t ceph_ll_snap_seq(class ceph_mount_info *cmount, Inode *in)
1743 {
1744   return (cmount->get_client()->ll_snap_seq(in));
1745 }
1746
1747 extern "C" int ceph_ll_get_stripe_osd(class ceph_mount_info *cmount,
1748                                       Inode *in, uint64_t blockno,
1749                                       struct ceph_file_layout* layout)
1750 {
1751   file_layout_t l;
1752   int r = (cmount->get_client()->ll_get_stripe_osd(in, blockno, &l));
1753   l.to_legacy(layout);
1754   return r;
1755 }
1756
1757 extern "C" int ceph_ll_num_osds(class ceph_mount_info *cmount)
1758 {
1759   return (cmount->get_client()->ll_num_osds());
1760 }
1761
1762 extern "C" int ceph_ll_osdaddr(class ceph_mount_info *cmount,
1763                                int osd, uint32_t *addr)
1764 {
1765   return (cmount->get_client()->ll_osdaddr(osd, addr));
1766 }
1767
1768 extern "C" uint64_t ceph_ll_get_internal_offset(class ceph_mount_info *cmount,
1769                                                 Inode *in,
1770                                                 uint64_t blockno)
1771 {
1772   return (cmount->get_client()->ll_get_internal_offset(in, blockno));
1773 }
1774
1775 extern "C" void ceph_buffer_free(char *buf)
1776 {
1777   if (buf) {
1778     free(buf);
1779   }
1780 }