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