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