]> git.proxmox.com Git - ceph.git/blame - ceph/src/os/FuseStore.cc
import 15.2.4
[ceph.git] / ceph / src / os / FuseStore.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
31f18b77 4#include "include/compat.h"
e306af50 5#include "include/ceph_fuse.h"
7c673cae
FG
6#include "FuseStore.h"
7#include "os/ObjectStore.h"
8#include "include/stringify.h"
9#include "common/errno.h"
10
1911f103 11#include <fuse_lowlevel.h>
7c673cae
FG
12
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <unistd.h>
16#include <fcntl.h> /* Definition of AT_* constants */
17#include <sys/stat.h>
18
11fdf7f2 19#if defined(__APPLE__) || defined(__FreeBSD__)
7c673cae
FG
20#include <sys/param.h>
21#include <sys/mount.h>
22#endif
23
24#define dout_context store->cct
25#define dout_subsys ceph_subsys_fuse
26#include "common/debug.h"
27#undef dout_prefix
28#define dout_prefix *_dout << "fuse "
29
30// some fuse-y bits of state
31struct fs_info {
32 struct fuse_args args;
33 struct fuse *f;
1911f103 34#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
7c673cae 35 struct fuse_chan *ch;
1911f103 36#endif
7c673cae
FG
37 char *mountpoint;
38};
39
40int FuseStore::open_file(string p, struct fuse_file_info *fi,
41 std::function<int(bufferlist *bl)> f)
42{
43 if (open_files.count(p)) {
44 OpenFile *o = open_files[p];
45 fi->fh = reinterpret_cast<uint64_t>(o);
46 ++o->ref;
47 return 0;
48 }
49 bufferlist bl;
50 int r = f(&bl);
51 if (r < 0) {
52 return r;
53 }
54 OpenFile *o = new OpenFile;
55 o->path = p;
56 o->bl.claim(bl);
57 open_files[p] = o;
58 fi->fh = reinterpret_cast<uint64_t>(o);
59 ++o->ref;
60 return 0;
61}
62
63FuseStore::FuseStore(ObjectStore *s, string p)
64 : store(s),
65 mount_point(p),
66 fuse_thread(this)
67{
68 info = new fs_info();
69}
70
71FuseStore::~FuseStore()
72{
73 delete info;
74}
75
76/*
77 * / - root directory
78 * $cid/
79 * $cid/type - objectstore type
80 * $cid/bitwise_hash_start = lowest hash value
81 * $cid/bitwise_hash_end = highest hash value
82 * $cid/bitwise_hash_bits - how many bits are significant
83 * $cid/pgmeta/ - pgmeta object
84 * $cid/all/ - all objects
85 * $cid/all/$obj/
86 * $cid/all/$obj/bitwise_hash
87 * $cid/all/$obj/data
88 * $cid/all/$obj/omap/$key
89 * $cid/all/$obj/attr/$name
90 * $cid/by_bitwise_hash/$hash/$bits/$obj - all objects with this (bitwise) hash (prefix)
91 */
92enum {
93 FN_ROOT = 1,
94 FN_TYPE,
95 FN_COLLECTION,
96 FN_HASH_START,
97 FN_HASH_END,
98 FN_HASH_BITS,
99 FN_OBJECT,
100 FN_OBJECT_HASH,
101 FN_OBJECT_DATA,
102 FN_OBJECT_OMAP_HEADER,
103 FN_OBJECT_OMAP,
104 FN_OBJECT_OMAP_VAL,
105 FN_OBJECT_ATTR,
106 FN_OBJECT_ATTR_VAL,
107 FN_ALL,
108 FN_HASH_DIR,
109 FN_HASH_VAL,
110};
111
112static int parse_fn(CephContext* cct, const char *path, coll_t *cid,
113 ghobject_t *oid, string *key,
114 uint32_t *hash, uint32_t *hash_bits)
115{
116 list<string> v;
117 for (const char *p = path; *p; ++p) {
118 if (*p == '/')
119 continue;
120 const char *e;
121 for (e = p + 1; *e && *e != '/'; e++) ;
122 string c(p, e-p);
123 v.push_back(c);
124 p = e;
125 if (!*p)
126 break;
127 }
128 ldout(cct, 10) << __func__ << " path " << path << " -> " << v << dendl;
129
130 if (v.empty())
131 return FN_ROOT;
132
133 if (v.front() == "type")
134 return FN_TYPE;
135
136 if (!cid->parse(v.front())) {
137 return -ENOENT;
138 }
139 if (v.size() == 1)
140 return FN_COLLECTION;
141 v.pop_front();
142
143 if (v.front() == "bitwise_hash_start")
144 return FN_HASH_START;
145 if (v.front() == "bitwise_hash_end")
146 return FN_HASH_END;
147 if (v.front() == "bitwise_hash_bits")
148 return FN_HASH_BITS;
149 if (v.front() == "pgmeta") {
150 spg_t pgid;
151 if (cid->is_pg(&pgid)) {
152 *oid = pgid.make_pgmeta_oid();
153 v.pop_front();
154 if (v.empty())
155 return FN_OBJECT;
156 goto do_object;
157 }
158 return -ENOENT;
159 }
160 if (v.front() == "all") {
161 v.pop_front();
162 if (v.empty())
163 return FN_ALL;
164 goto do_dir;
165 }
166 if (v.front() == "by_bitwise_hash") {
167 v.pop_front();
168 if (v.empty())
169 return FN_HASH_DIR;
170 unsigned long hv, hm;
171 int r = sscanf(v.front().c_str(), "%lx", &hv);
172 if (r != 1)
173 return -ENOENT;
174 int shift = 32 - v.front().length() * 4;
175 v.pop_front();
176 if (v.empty())
177 return FN_HASH_DIR;
178 r = sscanf(v.front().c_str(), "%ld", &hm);
179 if (r != 1)
180 return -ENOENT;
181 if (hm < 1 || hm > 32)
182 return -ENOENT;
183 v.pop_front();
184 *hash = hv << shift;//hobject_t::_reverse_bits(hv << shift);
185 *hash_bits = hm;
186 if (v.empty())
187 return FN_HASH_VAL;
188 goto do_dir;
189 }
190 return -ENOENT;
191
192 do_dir:
193 {
194 string o = v.front();
195 if (!oid->parse(o)) {
196 return -ENOENT;
197 }
198 v.pop_front();
199 if (v.empty())
200 return FN_OBJECT;
201 }
202
203 do_object:
204 if (v.front() == "data")
205 return FN_OBJECT_DATA;
206 if (v.front() == "omap_header")
207 return FN_OBJECT_OMAP_HEADER;
208 if (v.front() == "omap") {
209 v.pop_front();
210 if (v.empty())
211 return FN_OBJECT_OMAP;
212 *key = v.front();
213 v.pop_front();
214 if (v.empty())
215 return FN_OBJECT_OMAP_VAL;
216 return -ENOENT;
217 }
218 if (v.front() == "attr") {
219 v.pop_front();
220 if (v.empty())
221 return FN_OBJECT_ATTR;
222 *key = v.front();
223 v.pop_front();
224 if (v.empty())
225 return FN_OBJECT_ATTR_VAL;
226 return -ENOENT;
227 }
228 if (v.front() == "bitwise_hash")
229 return FN_OBJECT_HASH;
230 return -ENOENT;
231}
232
233
1911f103
TL
234static int os_getattr(const char *path, struct stat *stbuf
235#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
236 , struct fuse_file_info *fi
237#endif
238 )
7c673cae
FG
239{
240 fuse_context *fc = fuse_get_context();
241 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
242 ldout(fs->store->cct, 10) << __func__ << " " << path << dendl;
243 coll_t cid;
244 ghobject_t oid;
245 string key;
246 uint32_t hash_value, hash_bits;
247 int t = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
248 &hash_bits);
249 if (t < 0)
250 return t;
251
252 std::lock_guard<std::mutex> l(fs->lock);
253
254 stbuf->st_size = 0;
255 stbuf->st_uid = 0;
256 stbuf->st_gid = 0;
257 stbuf->st_mode = S_IFREG | 0700;
258
11fdf7f2
TL
259 auto ch = fs->store->open_collection(cid);
260
7c673cae
FG
261 switch (t) {
262 case FN_OBJECT_OMAP:
263 case FN_OBJECT_ATTR:
264 case FN_OBJECT:
265 case FN_OBJECT_DATA:
266 case FN_OBJECT_OMAP_HEADER:
267 case FN_OBJECT_OMAP_VAL:
268 {
269 spg_t pgid;
270 if (cid.is_pg(&pgid)) {
11fdf7f2
TL
271 if (!ch) {
272 return -ENOENT;
273 }
274 int bits = fs->store->collection_bits(ch);
7c673cae
FG
275 if (bits >= 0 && !oid.match(bits, pgid.ps())) {
276 // sorry, not part of this PG
277 return -ENOENT;
278 }
279 }
280 }
281 break;
282 }
283
284 switch (t) {
285 case FN_OBJECT_OMAP:
286 case FN_OBJECT_ATTR:
287 case FN_OBJECT:
11fdf7f2 288 if (!fs->store->exists(ch, oid))
7c673cae
FG
289 return -ENOENT;
290 // fall-thru
291 case FN_ALL:
292 case FN_HASH_DIR:
293 case FN_HASH_VAL:
294 case FN_COLLECTION:
295 if (!fs->store->collection_exists(cid))
296 return -ENOENT;
297 // fall-thru
298 case FN_ROOT:
299 stbuf->st_mode = S_IFDIR | 0700;
300 return 0;
301
302 case FN_TYPE:
303 stbuf->st_size = fs->store->get_type().length() + 1;
304 break;
305
306 case FN_OBJECT_HASH:
11fdf7f2 307 if (!fs->store->exists(ch, oid))
7c673cae
FG
308 return -ENOENT;
309 stbuf->st_size = 9;
310 return 0;
311
312 case FN_HASH_END:
11fdf7f2 313 if (!ch)
7c673cae 314 return -ENOENT;
11fdf7f2 315 if (fs->store->collection_bits(ch) < 0)
7c673cae
FG
316 return -ENOENT;
317 // fall-thru
318 case FN_HASH_START:
319 stbuf->st_size = 9;
320 return 0;
321
322 case FN_HASH_BITS:
323 {
11fdf7f2 324 if (!ch)
7c673cae 325 return -ENOENT;
11fdf7f2 326 int bits = fs->store->collection_bits(ch);
7c673cae
FG
327 if (bits < 0)
328 return -ENOENT;
11fdf7f2 329 char buf[12];
7c673cae
FG
330 snprintf(buf, sizeof(buf), "%d\n", bits);
331 stbuf->st_size = strlen(buf);
332 }
333 return 0;
334
335 case FN_OBJECT_DATA:
336 {
11fdf7f2 337 if (!fs->store->exists(ch, oid))
7c673cae 338 return -ENOENT;
11fdf7f2 339 int r = fs->store->stat(ch, oid, stbuf);
7c673cae
FG
340 if (r < 0)
341 return r;
342 }
343 break;
344
345 case FN_OBJECT_OMAP_HEADER:
346 {
11fdf7f2 347 if (!fs->store->exists(ch, oid))
7c673cae
FG
348 return -ENOENT;
349 bufferlist bl;
11fdf7f2 350 fs->store->omap_get_header(ch, oid, &bl);
7c673cae
FG
351 stbuf->st_size = bl.length();
352 }
353 break;
354
355 case FN_OBJECT_OMAP_VAL:
356 {
11fdf7f2 357 if (!fs->store->exists(ch, oid))
7c673cae
FG
358 return -ENOENT;
359 set<string> k;
360 k.insert(key);
361 map<string,bufferlist> v;
11fdf7f2 362 fs->store->omap_get_values(ch, oid, k, &v);
7c673cae
FG
363 if (!v.count(key)) {
364 return -ENOENT;
365 }
366 stbuf->st_size = v[key].length();
367 }
368 break;
369
370 case FN_OBJECT_ATTR_VAL:
371 {
11fdf7f2 372 if (!fs->store->exists(ch, oid))
7c673cae
FG
373 return -ENOENT;
374 bufferptr v;
11fdf7f2 375 int r = fs->store->getattr(ch, oid, key.c_str(), v);
7c673cae
FG
376 if (r == -ENODATA)
377 r = -ENOENT;
378 if (r < 0)
379 return r;
380 stbuf->st_size = v.length();
381 }
382 break;
383
384 default:
385 return -ENOENT;
386 }
387
388 return 0;
389}
390
391static int os_readdir(const char *path,
392 void *buf,
393 fuse_fill_dir_t filler,
394 off_t offset,
1911f103
TL
395 struct fuse_file_info *fi
396#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
397 , enum fuse_readdir_flags
398#endif
399 )
7c673cae
FG
400{
401 fuse_context *fc = fuse_get_context();
402 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
403 ldout(fs->store->cct, 10) << __func__ << " " << path << " offset " << offset
404 << dendl;
405 coll_t cid;
406 ghobject_t oid;
407 string key;
408 uint32_t hash_value, hash_bits;
409 int t = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
410 &hash_bits);
411 if (t < 0)
412 return t;
413
414 std::lock_guard<std::mutex> l(fs->lock);
415
11fdf7f2
TL
416 auto ch = fs->store->open_collection(cid);
417
7c673cae
FG
418 // we can't shift 32 bits or else off_t will go negative
419 const int hash_shift = 31;
420
421 switch (t) {
422 case FN_ROOT:
423 {
1911f103 424 filler_compat(filler, buf, "type", NULL, 0);
7c673cae
FG
425 vector<coll_t> cls;
426 fs->store->list_collections(cls);
427 for (auto c : cls) {
1911f103 428 int r = filler_compat(filler, buf, stringify(c).c_str(), NULL, 0);
7c673cae
FG
429 if (r > 0)
430 break;
431 }
432 }
433 break;
434
435 case FN_COLLECTION:
436 {
11fdf7f2
TL
437 if (!ch) {
438 return -ENOENT;
439 }
1911f103 440 filler_compat(filler, buf, "bitwise_hash_start", NULL, 0);
11fdf7f2 441 if (fs->store->collection_bits(ch) >= 0) {
1911f103
TL
442 filler_compat(filler, buf, "bitwise_hash_end", NULL, 0);
443 filler_compat(filler, buf, "bitwise_hash_bits", NULL, 0);
7c673cae 444 }
1911f103
TL
445 filler_compat(filler, buf, "all", NULL, 0);
446 filler_compat(filler, buf, "by_bitwise_hash", NULL, 0);
7c673cae
FG
447 spg_t pgid;
448 if (cid.is_pg(&pgid) &&
11fdf7f2 449 fs->store->exists(ch, pgid.make_pgmeta_oid())) {
1911f103 450 filler_compat(filler, buf, "pgmeta", NULL, 0);
7c673cae
FG
451 }
452 }
453 break;
454
455 case FN_OBJECT:
456 {
1911f103
TL
457 filler_compat(filler, buf, "bitwise_hash", NULL, 0);
458 filler_compat(filler, buf, "data", NULL, 0);
459 filler_compat(filler, buf, "omap", NULL, 0);
460 filler_compat(filler, buf, "attr", NULL, 0);
461 filler_compat(filler, buf, "omap_header", NULL, 0);
7c673cae
FG
462 }
463 break;
464
465 case FN_HASH_VAL:
466 case FN_ALL:
467 {
468 uint32_t bitwise_hash = (offset >> hash_shift) & 0xffffffff;
469 uint32_t hashoff = offset - (bitwise_hash << hash_shift);
470 int skip = hashoff;
471 ghobject_t next = cid.get_min_hobj();
472 if (offset) {
473 // obey the offset
474 next.hobj.set_hash(hobject_t::_reverse_bits(bitwise_hash));
475 } else if (t == FN_HASH_VAL) {
476 next.hobj.set_hash(hobject_t::_reverse_bits(hash_value));
477 }
478 ghobject_t last;
479 if (t == FN_HASH_VAL) {
480 last = next;
481 uint64_t rev_end = (hash_value | (0xffffffff >> hash_bits)) + 1;
482 if (rev_end >= 0x100000000)
483 last = ghobject_t::get_max();
484 else
485 last.hobj.set_hash(hobject_t::_reverse_bits(rev_end));
486 } else {
487 last = ghobject_t::get_max();
488 }
489 ldout(fs->store->cct, 10) << __func__ << std::hex
490 << " offset " << offset << " hash "
491 << hobject_t::_reverse_bits(hash_value)
492 << std::dec
493 << "/" << hash_bits
494 << " first " << next << " last " << last
495 << dendl;
496 while (true) {
497 vector<ghobject_t> ls;
498 int r = fs->store->collection_list(
11fdf7f2 499 ch, next, last, 1000, &ls, &next);
7c673cae
FG
500 if (r < 0)
501 return r;
502 for (auto p : ls) {
503 if (skip) {
504 --skip;
505 continue;
506 }
507 uint32_t cur_bitwise_hash = p.hobj.get_bitwise_key_u32();
508 if (cur_bitwise_hash != bitwise_hash) {
509 bitwise_hash = cur_bitwise_hash;
510 hashoff = 0;
511 }
512 ++hashoff;
513 uint64_t cur_off = ((uint64_t)bitwise_hash << hash_shift) |
514 (uint64_t)hashoff;
515 string s = stringify(p);
1911f103 516 r = filler_compat(filler, buf, s.c_str(), NULL, cur_off);
7c673cae
FG
517 if (r)
518 break;
519 }
520 if (r)
521 break;
522 if (next == ghobject_t::get_max() || next == last)
523 break;
524 }
525 }
526 break;
527
528 case FN_OBJECT_OMAP:
529 {
530 set<string> keys;
11fdf7f2 531 fs->store->omap_get_keys(ch, oid, &keys);
7c673cae
FG
532 unsigned skip = offset;
533 for (auto k : keys) {
534 if (skip) {
535 --skip;
536 continue;
537 }
538 ++offset;
1911f103 539 int r = filler_compat(filler, buf, k.c_str(), NULL, offset);
7c673cae
FG
540 if (r)
541 break;
542 }
543 }
544 break;
545
546 case FN_OBJECT_ATTR:
547 {
548 map<string,bufferptr> aset;
11fdf7f2 549 fs->store->getattrs(ch, oid, aset);
7c673cae
FG
550 unsigned skip = offset;
551 for (auto a : aset) {
552 if (skip) {
553 --skip;
554 continue;
555 }
556 ++offset;
1911f103 557 int r = filler_compat(filler, buf, a.first.c_str(), NULL, offset);
7c673cae
FG
558 if (r)
559 break;
560 }
561 }
562 break;
563 }
564 return 0;
565}
566
567static int os_open(const char *path, struct fuse_file_info *fi)
568{
569 fuse_context *fc = fuse_get_context();
570 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
571 ldout(fs->store->cct, 10) << __func__ << " " << path << dendl;
572 coll_t cid;
573 ghobject_t oid;
574 string key;
575 uint32_t hash_value, hash_bits;
576 int t = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
577 &hash_bits);
578 if (t < 0)
579 return t;
580
581 std::lock_guard<std::mutex> l(fs->lock);
582
11fdf7f2
TL
583 auto ch = fs->store->open_collection(cid);
584
7c673cae
FG
585 bufferlist *pbl = 0;
586 switch (t) {
587 case FN_TYPE:
588 pbl = new bufferlist;
589 pbl->append(fs->store->get_type());
590 pbl->append("\n");
591 break;
592
593 case FN_HASH_START:
594 {
595 pbl = new bufferlist;
596 spg_t pgid;
597 if (cid.is_pg(&pgid)) {
598 unsigned long h;
599 h = hobject_t::_reverse_bits(pgid.ps());
600 char buf[10];
601 snprintf(buf, sizeof(buf), "%08lx\n", h);
602 pbl->append(buf);
603 } else {
604 pbl->append("00000000\n");
605 }
606 }
607 break;
608
609 case FN_HASH_END:
610 {
11fdf7f2
TL
611 if (!ch) {
612 return -ENOENT;
613 }
7c673cae
FG
614 spg_t pgid;
615 unsigned long h;
616 if (cid.is_pg(&pgid)) {
11fdf7f2 617 int hash_bits = fs->store->collection_bits(ch);
7c673cae
FG
618 if (hash_bits >= 0) {
619 uint64_t rev_start = hobject_t::_reverse_bits(pgid.ps());
620 uint64_t rev_end = (rev_start | (0xffffffff >> hash_bits));
621 h = rev_end;
622 } else {
623 return -ENOENT;
624 }
625 } else {
626 h = 0xffffffff;
627 }
628 char buf[10];
629 snprintf(buf, sizeof(buf), "%08lx\n", h);
630 pbl = new bufferlist;
631 pbl->append(buf);
632 }
633 break;
634
635 case FN_HASH_BITS:
636 {
11fdf7f2
TL
637 if (!ch) {
638 return -ENOENT;
639 }
640 int r = fs->store->collection_bits(ch);
7c673cae
FG
641 if (r < 0)
642 return r;
11fdf7f2 643 char buf[12];
7c673cae
FG
644 snprintf(buf, sizeof(buf), "%d\n", r);
645 pbl = new bufferlist;
646 pbl->append(buf);
647 }
648 break;
649
650 case FN_OBJECT_HASH:
651 {
652 pbl = new bufferlist;
653 char buf[10];
654 snprintf(buf, sizeof(buf), "%08x\n",
655 (unsigned)oid.hobj.get_bitwise_key_u32());
656 pbl->append(buf);
657 }
658 break;
659
660 case FN_OBJECT_DATA:
661 {
662 int r = fs->open_file(
663 path, fi,
664 [&](bufferlist *pbl) {
11fdf7f2 665 return fs->store->read(ch, oid, 0, 0, *pbl);
7c673cae
FG
666 });
667 if (r < 0) {
668 return r;
669 }
670 }
671 break;
672
673 case FN_OBJECT_ATTR_VAL:
674 {
675 int r = fs->open_file(
676 path, fi,
677 [&](bufferlist *pbl) {
678 bufferptr bp;
11fdf7f2 679 int r = fs->store->getattr(ch, oid, key.c_str(), bp);
7c673cae
FG
680 if (r < 0)
681 return r;
682 pbl->append(bp);
683 return 0;
684 });
685 if (r < 0)
686 return r;
687 }
688 break;
689
690 case FN_OBJECT_OMAP_VAL:
691 {
692 int r = fs->open_file(
693 path, fi,
694 [&](bufferlist *pbl) {
695 set<string> k;
696 k.insert(key);
697 map<string,bufferlist> v;
11fdf7f2 698 int r = fs->store->omap_get_values(ch, oid, k, &v);
7c673cae
FG
699 if (r < 0)
700 return r;
701 *pbl = v[key];
702 return 0;
703 });
704 if (r < 0)
705 return r;
706 }
707 break;
708
709 case FN_OBJECT_OMAP_HEADER:
710 {
711 int r = fs->open_file(
712 path, fi,
713 [&](bufferlist *pbl) {
11fdf7f2 714 return fs->store->omap_get_header(ch, oid, pbl);
7c673cae
FG
715 });
716 if (r < 0)
717 return r;
718 }
719 break;
720 }
721
722 if (pbl) {
723 FuseStore::OpenFile *o = new FuseStore::OpenFile;
724 o->bl.claim(*pbl);
725 fi->fh = reinterpret_cast<uint64_t>(o);
726 }
727 return 0;
728}
729
730static int os_mkdir(const char *path, mode_t mode)
731{
732 fuse_context *fc = fuse_get_context();
733 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
734 ldout(fs->store->cct, 10) << __func__ << " " << path << dendl;
735 coll_t cid;
736 ghobject_t oid;
737 string key;
738 uint32_t hash_value, hash_bits;
739 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
740 &hash_bits);
741 if (f < 0)
742 return f;
743
744 std::lock_guard<std::mutex> l(fs->lock);
745
11fdf7f2
TL
746 ObjectStore::CollectionHandle ch;
747
7c673cae
FG
748 ObjectStore::Transaction t;
749 switch (f) {
750 case FN_OBJECT:
751 {
11fdf7f2
TL
752 ch = fs->store->open_collection(cid);
753 if (!ch) {
754 return -ENOENT;
755 }
7c673cae
FG
756 spg_t pgid;
757 if (cid.is_pg(&pgid)) {
11fdf7f2 758 int bits = fs->store->collection_bits(ch);
7c673cae
FG
759 if (bits >= 0 && !oid.match(bits, pgid.ps())) {
760 // sorry, not part of this PG
761 return -EINVAL;
762 }
763 }
764 t.touch(cid, oid);
11fdf7f2 765 ch = fs->store->open_collection(cid);
7c673cae
FG
766 }
767 break;
768
769 case FN_COLLECTION:
770 if (cid.is_pg()) {
771 // use the mode for the bit count. e.g., mkdir --mode=0003
772 // mnt/0.7_head will create 0.7 with bits = 3.
773 mode &= 0777;
774 if (mode >= 32)
775 return -EINVAL;
776 } else {
777 mode = 0;
778 }
779 t.create_collection(cid, mode);
11fdf7f2 780 ch = fs->store->create_new_collection(cid);
7c673cae
FG
781 break;
782
783 default:
784 return -EPERM;
785 }
786
787 if (!t.empty()) {
11fdf7f2 788 fs->store->queue_transaction(ch, std::move(t));
7c673cae
FG
789 }
790
791 return 0;
792}
793
1911f103
TL
794static int os_chmod(const char *path, mode_t mode
795#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
796 , struct fuse_file_info *fi
797#endif
798 )
7c673cae
FG
799{
800 fuse_context *fc = fuse_get_context();
801 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
802 ldout(fs->store->cct, 10) << __func__ << " " << path << dendl;
803 return 0;
804}
805
806static int os_create(const char *path, mode_t mode, struct fuse_file_info *fi)
807{
808 fuse_context *fc = fuse_get_context();
809 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
810 ldout(fs->store->cct, 10) << __func__ << " " << path << dendl;
811 coll_t cid;
812 ghobject_t oid;
813 string key;
814 uint32_t hash_value, hash_bits;
815 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
816 &hash_bits);
817 if (f < 0)
818 return f;
819
820 std::lock_guard<std::mutex> l(fs->lock);
821
11fdf7f2
TL
822 ObjectStore::CollectionHandle ch = fs->store->open_collection(cid);
823
7c673cae
FG
824 ObjectStore::Transaction t;
825 bufferlist *pbl = 0;
826 switch (f) {
827 case FN_OBJECT_DATA:
828 {
829 pbl = new bufferlist;
11fdf7f2 830 fs->store->read(ch, oid, 0, 0, *pbl);
7c673cae
FG
831 }
832 break;
833
834 case FN_OBJECT_ATTR_VAL:
835 {
836 pbl = new bufferlist;
837 bufferptr bp;
11fdf7f2 838 int r = fs->store->getattr(ch, oid, key.c_str(), bp);
7c673cae
FG
839 if (r == -ENODATA) {
840 bufferlist empty;
841 t.setattr(cid, oid, key.c_str(), empty);
842 }
843 pbl->append(bp);
844 }
845 break;
846
847 case FN_OBJECT_OMAP_VAL:
848 {
849 pbl = new bufferlist;
850 set<string> k;
851 k.insert(key);
852 map<string,bufferlist> v;
11fdf7f2 853 fs->store->omap_get_values(ch, oid, k, &v);
7c673cae
FG
854 if (v.count(key) == 0) {
855 map<string,bufferlist> aset;
856 aset[key] = bufferlist();
857 t.omap_setkeys(cid, oid, aset);
858 } else {
859 *pbl = v[key];
860 }
861 }
862 break;
863 }
864
865 if (!t.empty()) {
11fdf7f2 866 fs->store->queue_transaction(ch, std::move(t));
7c673cae
FG
867 }
868
869 if (pbl) {
870 FuseStore::OpenFile *o = new FuseStore::OpenFile;
871 o->bl.claim(*pbl);
872 o->dirty = true;
873 fi->fh = reinterpret_cast<uint64_t>(o);
874 }
875 return 0;
876}
877
878static int os_release(const char *path, struct fuse_file_info *fi)
879{
880 fuse_context *fc = fuse_get_context();
881 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
882 ldout(fs->store->cct, 10) << __func__ << " " << path << dendl;
883 std::lock_guard<std::mutex> l(fs->lock);
884 FuseStore::OpenFile *o = reinterpret_cast<FuseStore::OpenFile*>(fi->fh);
885 if (--o->ref == 0) {
886 ldout(fs->store->cct, 10) << __func__ << " closing last " << o->path << dendl;
887 fs->open_files.erase(o->path);
888 delete o;
889 }
890 return 0;
891}
892
893static int os_read(const char *path, char *buf, size_t size, off_t offset,
894 struct fuse_file_info *fi)
895{
896 fuse_context *fc = fuse_get_context();
897 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
898 ldout(fs->store->cct, 10) << __func__ << " " << path << " offset " << offset
899 << " size " << size << dendl;
900 std::lock_guard<std::mutex> l(fs->lock);
901 FuseStore::OpenFile *o = reinterpret_cast<FuseStore::OpenFile*>(fi->fh);
902 if (!o)
903 return 0;
904 if (offset >= o->bl.length())
905 return 0;
906 if (offset + size > o->bl.length())
907 size = o->bl.length() - offset;
908 bufferlist r;
909 r.substr_of(o->bl, offset, size);
910 memcpy(buf, r.c_str(), r.length());
911 return r.length();
912}
913
914static int os_write(const char *path, const char *buf, size_t size,
915 off_t offset, struct fuse_file_info *fi)
916{
917 fuse_context *fc = fuse_get_context();
918 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
919 ldout(fs->store->cct, 10) << __func__ << " " << path << " offset " << offset
920 << " size " << size << dendl;
921 std::lock_guard<std::mutex> l(fs->lock);
922 FuseStore::OpenFile *o = reinterpret_cast<FuseStore::OpenFile*>(fi->fh);
923 if (!o)
924 return 0;
925
926 bufferlist final;
927 if (offset) {
928 if (offset > o->bl.length()) {
929 final.substr_of(o->bl, 0, offset);
930 } else {
931 final.claim_append(o->bl);
932 size_t zlen = offset - final.length();
933 final.append_zero(zlen);
934 }
935 }
936 final.append(buf, size);
937 if (offset + size < o->bl.length()) {
938 bufferlist rest;
939 rest.substr_of(o->bl, offset + size, o->bl.length() - offset - size);
940 final.claim_append(rest);
941 }
942 o->bl = final;
943 o->dirty = true;
944 return size;
945}
946
947int os_flush(const char *path, struct fuse_file_info *fi)
948{
949 fuse_context *fc = fuse_get_context();
950 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
951 ldout(fs->store->cct, 10) << __func__ << " " << path << dendl;
952 coll_t cid;
953 ghobject_t oid;
954 string key;
955 uint32_t hash_value, hash_bits;
956 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
957 &hash_bits);
958 if (f < 0)
959 return f;
960
961 std::lock_guard<std::mutex> l(fs->lock);
962
963 FuseStore::OpenFile *o = reinterpret_cast<FuseStore::OpenFile*>(fi->fh);
964 if (!o)
965 return 0;
966 if (!o->dirty)
967 return 0;
968
11fdf7f2
TL
969 ObjectStore::CollectionHandle ch = fs->store->open_collection(cid);
970
7c673cae
FG
971 ObjectStore::Transaction t;
972
973 switch (f) {
974 case FN_OBJECT_DATA:
975 t.write(cid, oid, 0, o->bl.length(), o->bl);
976 break;
977
978 case FN_OBJECT_ATTR_VAL:
979 t.setattr(cid, oid, key.c_str(), o->bl);
980 break;
981
982 case FN_OBJECT_OMAP_VAL:
983 {
984 map<string,bufferlist> aset;
985 aset[key] = o->bl;
986 t.omap_setkeys(cid, oid, aset);
987 break;
988 }
989
990 case FN_OBJECT_OMAP_HEADER:
991 t.omap_setheader(cid, oid, o->bl);
992 break;
993
994 default:
995 return 0;
996 }
997
11fdf7f2 998 fs->store->queue_transaction(ch, std::move(t));
7c673cae
FG
999
1000 return 0;
1001}
1002
1003static int os_unlink(const char *path)
1004{
1005 fuse_context *fc = fuse_get_context();
1006 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
1007 ldout(fs->store->cct, 10) << __func__ << " " << path << dendl;
1008 coll_t cid;
1009 ghobject_t oid;
1010 string key;
1011 uint32_t hash_value, hash_bits;
1012 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
1013 &hash_bits);
1014 if (f < 0)
1015 return f;
1016
1017 std::lock_guard<std::mutex> l(fs->lock);
1018
11fdf7f2 1019 ObjectStore::CollectionHandle ch = fs->store->open_collection(cid);
7c673cae
FG
1020 ObjectStore::Transaction t;
1021
1022 switch (f) {
1023 case FN_OBJECT_OMAP_VAL:
1024 {
9f95a23c 1025 t.omap_rmkey(cid, oid, key);
7c673cae
FG
1026 }
1027 break;
1028
1029 case FN_OBJECT_ATTR_VAL:
1030 t.rmattr(cid, oid, key.c_str());
1031 break;
1032
1033 case FN_OBJECT_OMAP_HEADER:
1034 {
1035 bufferlist empty;
1036 t.omap_setheader(cid, oid, empty);
1037 }
1038 break;
1039
1040 case FN_OBJECT:
1041 t.remove(cid, oid);
1042 break;
1043
1044 case FN_COLLECTION:
1045 {
1046 bool empty;
11fdf7f2 1047 int r = fs->store->collection_empty(ch, &empty);
7c673cae
FG
1048 if (r < 0)
1049 return r;
1050 if (!empty)
1051 return -ENOTEMPTY;
1052 t.remove_collection(cid);
1053 }
1054 break;
1055
1056 case FN_OBJECT_DATA:
1057 t.truncate(cid, oid, 0);
1058 break;
1059
1060 default:
1061 return -EPERM;
1062 }
1063
11fdf7f2 1064 fs->store->queue_transaction(ch, std::move(t));
7c673cae
FG
1065
1066 return 0;
1067}
1068
1911f103
TL
1069static int os_truncate(const char *path, off_t size
1070#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1071 , struct fuse_file_info *fi
1072#endif
1073 )
7c673cae
FG
1074{
1075 fuse_context *fc = fuse_get_context();
1076 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
1077 ldout(fs->store->cct, 10) << __func__ << " " << path << " size " << size << dendl;
1078 coll_t cid;
1079 ghobject_t oid;
1080 string key;
1081 uint32_t hash_value, hash_bits;
1082 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
1083 &hash_bits);
1084 if (f < 0)
1085 return f;
1086
1087 if (f == FN_OBJECT_OMAP_VAL ||
1088 f == FN_OBJECT_ATTR_VAL ||
1089 f == FN_OBJECT_OMAP_HEADER) {
1090 if (size)
1091 return -EPERM;
1092 return 0;
1093 }
1094 if (f != FN_OBJECT_DATA)
1095 return -EPERM;
1096
1097 std::lock_guard<std::mutex> l(fs->lock);
1098
1099 if (fs->open_files.count(path)) {
1100 FuseStore::OpenFile *o = fs->open_files[path];
1101 if (o->bl.length() > size) {
1102 bufferlist t;
1103 t.substr_of(o->bl, 0, size);
1104 o->bl.swap(t);
1105 }
1106 }
1107
11fdf7f2 1108 ObjectStore::CollectionHandle ch = fs->store->open_collection(cid);
7c673cae
FG
1109 ObjectStore::Transaction t;
1110 t.truncate(cid, oid, size);
11fdf7f2 1111 fs->store->queue_transaction(ch, std::move(t));
7c673cae
FG
1112 return 0;
1113}
1114
1115static int os_statfs(const char *path, struct statvfs *stbuf)
1116{
1117 fuse_context *fc = fuse_get_context();
1118 FuseStore *fs = static_cast<FuseStore*>(fc->private_data);
1119 ldout(fs->store->cct, 10) << __func__ << " " << path << dendl;
1120 std::lock_guard<std::mutex> l(fs->lock);
1121
1122 struct store_statfs_t s;
1123 int r = fs->store->statfs(&s);
1124 if (r < 0)
1125 return r;
1126 stbuf->f_bsize = 4096; // LIES!
1127 stbuf->f_blocks = s.total / 4096;
1128 stbuf->f_bavail = s.available / 4096;
11fdf7f2 1129 stbuf->f_bfree = stbuf->f_bavail;
7c673cae 1130
11fdf7f2
TL
1131 ldout(fs->store->cct, 10) << __func__ << " " << path << ": "
1132 << stbuf->f_bavail << "/" << stbuf->f_blocks << dendl;
7c673cae
FG
1133 return 0;
1134}
1135
1136static struct fuse_operations fs_oper = {
1137 getattr: os_getattr,
1138 readlink: 0,
1911f103 1139#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
7c673cae 1140 getdir: 0,
1911f103 1141#endif
7c673cae
FG
1142 mknod: 0,
1143 mkdir: os_mkdir,
1144 unlink: os_unlink,
1145 rmdir: os_unlink,
1146 symlink: 0,
1147 rename: 0,
1148 link: 0,
1149 chmod: os_chmod,
1150 chown: 0,
1151 truncate: os_truncate,
1911f103 1152#if FUSE_VERSION < FUSE_MAKE_VERSION(3, 0)
7c673cae 1153 utime: 0,
1911f103 1154#endif
7c673cae
FG
1155 open: os_open,
1156 read: os_read,
1157 write: os_write,
1158 statfs: os_statfs,
1159 flush: os_flush,
1160 release: os_release,
1161 fsync: 0,
1162 setxattr: 0,
1163 getxattr: 0,
1164 listxattr: 0,
1165 removexattr: 0,
1166 opendir: 0,
1167 readdir: os_readdir,
1168 releasedir: 0,
1169 fsyncdir: 0,
1170 init: 0,
1171 destroy: 0,
1172 access: 0,
1173 create: os_create,
1174};
1175
1176int FuseStore::main()
1177{
1178 const char *v[] = {
1179 "foo",
1180 mount_point.c_str(),
1181 "-f",
1182 "-d", // debug
1183 };
1184 int c = 3;
11fdf7f2
TL
1185 auto fuse_debug = store->cct->_conf.get_val<bool>("fuse_debug");
1186 if (fuse_debug)
7c673cae
FG
1187 ++c;
1188 return fuse_main(c, (char**)v, &fs_oper, (void*)this);
1189}
1190
1191int FuseStore::start()
1192{
1193 dout(10) << __func__ << dendl;
1194
1195 memset(&info->args, 0, sizeof(info->args));
1196 const char *v[] = {
1197 "foo",
1198 mount_point.c_str(),
1199 "-f", // foreground
1200 "-d", // debug
1201 };
1202 int c = 3;
1911f103
TL
1203#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1204 int rc;
1205 struct fuse_cmdline_opts opts = {};
1206#endif
11fdf7f2
TL
1207 auto fuse_debug = store->cct->_conf.get_val<bool>("fuse_debug");
1208 if (fuse_debug)
7c673cae
FG
1209 ++c;
1210 fuse_args a = FUSE_ARGS_INIT(c, (char**)v);
1211 info->args = a;
1911f103
TL
1212#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1213 if (fuse_parse_cmdline(&info->args, &opts) == -1) {
1214#else
7c673cae 1215 if (fuse_parse_cmdline(&info->args, &info->mountpoint, NULL, NULL) == -1) {
1911f103 1216#endif
7c673cae
FG
1217 derr << __func__ << " failed to parse args" << dendl;
1218 return -EINVAL;
1219 }
1220
1911f103
TL
1221#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1222 info->mountpoint = opts.mountpoint;
1223 info->f = fuse_new(&info->args, &fs_oper, sizeof(fs_oper), (void*)this);
1224 if (!info->f) {
1225 derr << __func__ << " fuse_new failed" << dendl;
1226 return -EIO;
1227 }
1228
1229 rc = fuse_mount(info->f, info->mountpoint);
1230 if (rc != 0) {
1231 derr << __func__ << " fuse_mount failed" << dendl;
1232 return -EIO;
1233 }
1234#else
7c673cae
FG
1235 info->ch = fuse_mount(info->mountpoint, &info->args);
1236 if (!info->ch) {
1237 derr << __func__ << " fuse_mount failed" << dendl;
1238 return -EIO;
1239 }
1240
1241 info->f = fuse_new(info->ch, &info->args, &fs_oper, sizeof(fs_oper),
1242 (void*)this);
1243 if (!info->f) {
1244 fuse_unmount(info->mountpoint, info->ch);
1245 derr << __func__ << " fuse_new failed" << dendl;
1246 return -EIO;
1247 }
1911f103 1248#endif
7c673cae
FG
1249
1250 fuse_thread.create("fusestore");
1251 dout(10) << __func__ << " done" << dendl;
1252 return 0;
1253}
1254
1255int FuseStore::loop()
1256{
1257 dout(10) << __func__ << " enter" << dendl;
1258 int r = fuse_loop(info->f);
1259 if (r)
1260 derr << __func__ << " got " << cpp_strerror(r) << dendl;
1261 dout(10) << __func__ << " exit" << dendl;
1262 return r;
1263}
1264
1265int FuseStore::stop()
1266{
1267 dout(10) << __func__ << " enter" << dendl;
1911f103
TL
1268#if FUSE_VERSION >= FUSE_MAKE_VERSION(3, 0)
1269 fuse_unmount(info->f);
1270#else
7c673cae 1271 fuse_unmount(info->mountpoint, info->ch);
1911f103 1272#endif
7c673cae
FG
1273 fuse_thread.join();
1274 fuse_destroy(info->f);
1275 dout(10) << __func__ << " exit" << dendl;
1276 return 0;
1277}