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