1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/compat.h"
6 #include "os/ObjectStore.h"
7 #include "include/stringify.h"
8 #include "common/errno.h"
10 #define FUSE_USE_VERSION 30
13 #include <sys/types.h>
16 #include <fcntl.h> /* Definition of AT_* constants */
19 #if defined(DARWIN) || defined(__FreeBSD__)
20 #include <sys/param.h>
21 #include <sys/mount.h>
24 #define dout_context store->cct
25 #define dout_subsys ceph_subsys_fuse
26 #include "common/debug.h"
28 #define dout_prefix *_dout << "fuse "
30 // some fuse-y bits of state
32 struct fuse_args args;
38 int FuseStore::open_file(string p, struct fuse_file_info *fi,
39 std::function<int(bufferlist *bl)> f)
41 if (open_files.count(p)) {
42 OpenFile *o = open_files[p];
43 fi->fh = reinterpret_cast<uint64_t>(o);
52 OpenFile *o = new OpenFile;
56 fi->fh = reinterpret_cast<uint64_t>(o);
61 FuseStore::FuseStore(ObjectStore *s, string p)
69 FuseStore::~FuseStore()
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
84 * $cid/all/$obj/bitwise_hash
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)
100 FN_OBJECT_OMAP_HEADER,
110 static 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)
115 for (const char *p = path; *p; ++p) {
119 for (e = p + 1; *e && *e != '/'; e++) ;
126 ldout(cct, 10) << __func__ << " path " << path << " -> " << v << dendl;
131 if (v.front() == "type")
134 if (!cid->parse(v.front())) {
138 return FN_COLLECTION;
141 if (v.front() == "bitwise_hash_start")
142 return FN_HASH_START;
143 if (v.front() == "bitwise_hash_end")
145 if (v.front() == "bitwise_hash_bits")
147 if (v.front() == "pgmeta") {
149 if (cid->is_pg(&pgid)) {
150 *oid = pgid.make_pgmeta_oid();
158 if (v.front() == "all") {
164 if (v.front() == "by_bitwise_hash") {
168 unsigned long hv, hm;
169 int r = sscanf(v.front().c_str(), "%lx", &hv);
172 int shift = 32 - v.front().length() * 4;
176 r = sscanf(v.front().c_str(), "%ld", &hm);
179 if (hm < 1 || hm > 32)
182 *hash = hv << shift;//hobject_t::_reverse_bits(hv << shift);
192 string o = v.front();
193 if (!oid->parse(o)) {
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") {
209 return FN_OBJECT_OMAP;
213 return FN_OBJECT_OMAP_VAL;
216 if (v.front() == "attr") {
219 return FN_OBJECT_ATTR;
223 return FN_OBJECT_ATTR_VAL;
226 if (v.front() == "bitwise_hash")
227 return FN_OBJECT_HASH;
232 static int os_getattr(const char *path, struct stat *stbuf)
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;
240 uint32_t hash_value, hash_bits;
241 int t = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
246 std::lock_guard<std::mutex> l(fs->lock);
251 stbuf->st_mode = S_IFREG | 0700;
258 case FN_OBJECT_OMAP_HEADER:
259 case FN_OBJECT_OMAP_VAL:
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
277 if (!fs->store->exists(cid, oid))
284 if (!fs->store->collection_exists(cid))
288 stbuf->st_mode = S_IFDIR | 0700;
292 stbuf->st_size = fs->store->get_type().length() + 1;
296 if (!fs->store->exists(cid, oid))
302 if (!fs->store->collection_exists(cid))
304 if (fs->store->collection_bits(cid) < 0)
313 if (!fs->store->collection_exists(cid))
315 int bits = fs->store->collection_bits(cid);
319 snprintf(buf, sizeof(buf), "%d\n", bits);
320 stbuf->st_size = strlen(buf);
326 if (!fs->store->exists(cid, oid))
328 int r = fs->store->stat(cid, oid, stbuf);
334 case FN_OBJECT_OMAP_HEADER:
336 if (!fs->store->exists(cid, oid))
339 fs->store->omap_get_header(cid, oid, &bl);
340 stbuf->st_size = bl.length();
344 case FN_OBJECT_OMAP_VAL:
346 if (!fs->store->exists(cid, oid))
350 map<string,bufferlist> v;
351 fs->store->omap_get_values(cid, oid, k, &v);
355 stbuf->st_size = v[key].length();
359 case FN_OBJECT_ATTR_VAL:
361 if (!fs->store->exists(cid, oid))
364 int r = fs->store->getattr(cid, oid, key.c_str(), v);
369 stbuf->st_size = v.length();
380 static int os_readdir(const char *path,
382 fuse_fill_dir_t filler,
384 struct fuse_file_info *fi)
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
393 uint32_t hash_value, hash_bits;
394 int t = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
399 std::lock_guard<std::mutex> l(fs->lock);
401 // we can't shift 32 bits or else off_t will go negative
402 const int hash_shift = 31;
407 filler(buf, "type", NULL, 0);
409 fs->store->list_collections(cls);
411 int r = filler(buf, stringify(c).c_str(), NULL, 0);
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);
425 filler(buf, "all", NULL, 0);
426 filler(buf, "by_bitwise_hash", NULL, 0);
428 if (cid.is_pg(&pgid) &&
429 fs->store->exists(cid, pgid.make_pgmeta_oid())) {
430 filler(buf, "pgmeta", NULL, 0);
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);
448 uint32_t bitwise_hash = (offset >> hash_shift) & 0xffffffff;
449 uint32_t hashoff = offset - (bitwise_hash << hash_shift);
451 ghobject_t next = cid.get_min_hobj();
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));
459 if (t == FN_HASH_VAL) {
461 uint64_t rev_end = (hash_value | (0xffffffff >> hash_bits)) + 1;
462 if (rev_end >= 0x100000000)
463 last = ghobject_t::get_max();
465 last.hobj.set_hash(hobject_t::_reverse_bits(rev_end));
467 last = ghobject_t::get_max();
469 ldout(fs->store->cct, 10) << __func__ << std::hex
470 << " offset " << offset << " hash "
471 << hobject_t::_reverse_bits(hash_value)
474 << " first " << next << " last " << last
477 vector<ghobject_t> ls;
478 int r = fs->store->collection_list(
479 cid, next, last, 1000, &ls, &next);
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;
493 uint64_t cur_off = ((uint64_t)bitwise_hash << hash_shift) |
495 string s = stringify(p);
496 r = filler(buf, s.c_str(), NULL, cur_off);
502 if (next == ghobject_t::get_max() || next == last)
511 fs->store->omap_get_keys(cid, oid, &keys);
512 unsigned skip = offset;
513 for (auto k : keys) {
519 int r = filler(buf, k.c_str(), NULL, offset);
528 map<string,bufferptr> aset;
529 fs->store->getattrs(cid, oid, aset);
530 unsigned skip = offset;
531 for (auto a : aset) {
537 int r = filler(buf, a.first.c_str(), NULL, offset);
547 static int os_open(const char *path, struct fuse_file_info *fi)
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;
555 uint32_t hash_value, hash_bits;
556 int t = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
561 std::lock_guard<std::mutex> l(fs->lock);
566 pbl = new bufferlist;
567 pbl->append(fs->store->get_type());
573 pbl = new bufferlist;
575 if (cid.is_pg(&pgid)) {
577 h = hobject_t::_reverse_bits(pgid.ps());
579 snprintf(buf, sizeof(buf), "%08lx\n", h);
582 pbl->append("00000000\n");
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));
604 snprintf(buf, sizeof(buf), "%08lx\n", h);
605 pbl = new bufferlist;
612 int r = fs->store->collection_bits(cid);
616 snprintf(buf, sizeof(buf), "%d\n", r);
617 pbl = new bufferlist;
624 pbl = new bufferlist;
626 snprintf(buf, sizeof(buf), "%08x\n",
627 (unsigned)oid.hobj.get_bitwise_key_u32());
634 int r = fs->open_file(
636 [&](bufferlist *pbl) {
637 return fs->store->read(cid, oid, 0, 0, *pbl);
645 case FN_OBJECT_ATTR_VAL:
647 int r = fs->open_file(
649 [&](bufferlist *pbl) {
651 int r = fs->store->getattr(cid, oid, key.c_str(), bp);
662 case FN_OBJECT_OMAP_VAL:
664 int r = fs->open_file(
666 [&](bufferlist *pbl) {
669 map<string,bufferlist> v;
670 int r = fs->store->omap_get_values(cid, oid, k, &v);
681 case FN_OBJECT_OMAP_HEADER:
683 int r = fs->open_file(
685 [&](bufferlist *pbl) {
686 return fs->store->omap_get_header(cid, oid, pbl);
695 FuseStore::OpenFile *o = new FuseStore::OpenFile;
697 fi->fh = reinterpret_cast<uint64_t>(o);
702 static int os_mkdir(const char *path, mode_t mode)
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;
710 uint32_t hash_value, hash_bits;
711 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
716 std::lock_guard<std::mutex> l(fs->lock);
718 ObjectStore::Transaction t;
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
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.
744 t.create_collection(cid, mode);
752 ceph::shared_ptr<ObjectStore::Sequencer> osr(
753 new ObjectStore::Sequencer("fuse"));
754 fs->store->apply_transaction(&*osr, std::move(t));
756 if (!osr->flush_commit(&waiter))
763 static int os_chmod(const char *path, mode_t mode)
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;
771 static int os_create(const char *path, mode_t mode, struct fuse_file_info *fi)
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;
779 uint32_t hash_value, hash_bits;
780 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
785 std::lock_guard<std::mutex> l(fs->lock);
787 ObjectStore::Transaction t;
792 pbl = new bufferlist;
793 fs->store->read(cid, oid, 0, 0, *pbl);
797 case FN_OBJECT_ATTR_VAL:
799 pbl = new bufferlist;
801 int r = fs->store->getattr(cid, oid, key.c_str(), bp);
804 t.setattr(cid, oid, key.c_str(), empty);
810 case FN_OBJECT_OMAP_VAL:
812 pbl = new bufferlist;
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);
829 ceph::shared_ptr<ObjectStore::Sequencer> osr(
830 new ObjectStore::Sequencer("fuse"));
831 fs->store->apply_transaction(&*osr, std::move(t));
833 if (!osr->flush_commit(&waiter))
838 FuseStore::OpenFile *o = new FuseStore::OpenFile;
841 fi->fh = reinterpret_cast<uint64_t>(o);
846 static int os_release(const char *path, struct fuse_file_info *fi)
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);
854 ldout(fs->store->cct, 10) << __func__ << " closing last " << o->path << dendl;
855 fs->open_files.erase(o->path);
861 static int os_read(const char *path, char *buf, size_t size, off_t offset,
862 struct fuse_file_info *fi)
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);
872 if (offset >= o->bl.length())
874 if (offset + size > o->bl.length())
875 size = o->bl.length() - offset;
877 r.substr_of(o->bl, offset, size);
878 memcpy(buf, r.c_str(), r.length());
882 static int os_write(const char *path, const char *buf, size_t size,
883 off_t offset, struct fuse_file_info *fi)
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);
896 if (offset > o->bl.length()) {
897 final.substr_of(o->bl, 0, offset);
899 final.claim_append(o->bl);
900 size_t zlen = offset - final.length();
901 final.append_zero(zlen);
904 final.append(buf, size);
905 if (offset + size < o->bl.length()) {
907 rest.substr_of(o->bl, offset + size, o->bl.length() - offset - size);
908 final.claim_append(rest);
915 int os_flush(const char *path, struct fuse_file_info *fi)
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;
923 uint32_t hash_value, hash_bits;
924 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
929 std::lock_guard<std::mutex> l(fs->lock);
931 FuseStore::OpenFile *o = reinterpret_cast<FuseStore::OpenFile*>(fi->fh);
937 ObjectStore::Transaction t;
941 t.write(cid, oid, 0, o->bl.length(), o->bl);
944 case FN_OBJECT_ATTR_VAL:
945 t.setattr(cid, oid, key.c_str(), o->bl);
948 case FN_OBJECT_OMAP_VAL:
950 map<string,bufferlist> aset;
952 t.omap_setkeys(cid, oid, aset);
956 case FN_OBJECT_OMAP_HEADER:
957 t.omap_setheader(cid, oid, o->bl);
964 ceph::shared_ptr<ObjectStore::Sequencer> osr(
965 new ObjectStore::Sequencer("fuse"));
966 fs->store->apply_transaction(&*osr, std::move(t));
968 if (!osr->flush_commit(&waiter))
974 static int os_unlink(const char *path)
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;
982 uint32_t hash_value, hash_bits;
983 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
988 std::lock_guard<std::mutex> l(fs->lock);
990 ObjectStore::Transaction t;
993 case FN_OBJECT_OMAP_VAL:
997 t.omap_rmkeys(cid, oid, keys);
1001 case FN_OBJECT_ATTR_VAL:
1002 t.rmattr(cid, oid, key.c_str());
1005 case FN_OBJECT_OMAP_HEADER:
1008 t.omap_setheader(cid, oid, empty);
1019 int r = fs->store->collection_empty(cid, &empty);
1024 t.remove_collection(cid);
1028 case FN_OBJECT_DATA:
1029 t.truncate(cid, oid, 0);
1036 ceph::shared_ptr<ObjectStore::Sequencer> osr(
1037 new ObjectStore::Sequencer("fuse"));
1038 fs->store->apply_transaction(&*osr, std::move(t));
1040 if (!osr->flush_commit(&waiter))
1046 static int os_truncate(const char *path, off_t size)
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;
1054 uint32_t hash_value, hash_bits;
1055 int f = parse_fn(fs->store->cct, path, &cid, &oid, &key, &hash_value,
1060 if (f == FN_OBJECT_OMAP_VAL ||
1061 f == FN_OBJECT_ATTR_VAL ||
1062 f == FN_OBJECT_OMAP_HEADER) {
1067 if (f != FN_OBJECT_DATA)
1070 std::lock_guard<std::mutex> l(fs->lock);
1072 if (fs->open_files.count(path)) {
1073 FuseStore::OpenFile *o = fs->open_files[path];
1074 if (o->bl.length() > size) {
1076 t.substr_of(o->bl, 0, size);
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));
1087 if (!osr->flush_commit(&waiter))
1092 static int os_statfs(const char *path, struct statvfs *stbuf)
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);
1099 struct store_statfs_t s;
1100 int r = fs->store->statfs(&s);
1103 stbuf->f_bsize = 4096; // LIES!
1104 stbuf->f_blocks = s.total / 4096;
1105 stbuf->f_bavail = s.available / 4096;
1110 static struct fuse_operations fs_oper = {
1111 getattr: os_getattr,
1123 truncate: os_truncate,
1130 release: os_release,
1137 readdir: os_readdir,
1146 int FuseStore::main()
1150 mount_point.c_str(),
1155 if (store->cct->_conf->fuse_debug)
1157 return fuse_main(c, (char**)v, &fs_oper, (void*)this);
1160 int FuseStore::start()
1162 dout(10) << __func__ << dendl;
1164 memset(&info->args, 0, sizeof(info->args));
1167 mount_point.c_str(),
1172 if (store->cct->_conf->fuse_debug)
1174 fuse_args a = FUSE_ARGS_INIT(c, (char**)v);
1176 if (fuse_parse_cmdline(&info->args, &info->mountpoint, NULL, NULL) == -1) {
1177 derr << __func__ << " failed to parse args" << dendl;
1181 info->ch = fuse_mount(info->mountpoint, &info->args);
1183 derr << __func__ << " fuse_mount failed" << dendl;
1187 info->f = fuse_new(info->ch, &info->args, &fs_oper, sizeof(fs_oper),
1190 fuse_unmount(info->mountpoint, info->ch);
1191 derr << __func__ << " fuse_new failed" << dendl;
1195 fuse_thread.create("fusestore");
1196 dout(10) << __func__ << " done" << dendl;
1200 int FuseStore::loop()
1202 dout(10) << __func__ << " enter" << dendl;
1203 int r = fuse_loop(info->f);
1205 derr << __func__ << " got " << cpp_strerror(r) << dendl;
1206 dout(10) << __func__ << " exit" << dendl;
1210 int FuseStore::stop()
1212 dout(10) << __func__ << " enter" << dendl;
1213 fuse_unmount(info->mountpoint, info->ch);
1215 fuse_destroy(info->f);
1216 dout(10) << __func__ << " exit" << dendl;