X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Frgw%2Frgw_file.h;fp=src%2Fceph%2Fsrc%2Frgw%2Frgw_file.h;h=0000000000000000000000000000000000000000;hb=7da45d65be36d36b880cc55c5036e96c24b53f00;hp=2f8b8bad140cffa2df3327d82e592d1ea85be5bb;hpb=691462d09d0987b47e112d6ee8740375df3c51b2;p=stor4nfv.git diff --git a/src/ceph/src/rgw/rgw_file.h b/src/ceph/src/rgw/rgw_file.h deleted file mode 100644 index 2f8b8ba..0000000 --- a/src/ceph/src/rgw/rgw_file.h +++ /dev/null @@ -1,2512 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#ifndef RGW_FILE_H -#define RGW_FILE_H - -#include "include/rados/rgw_file.h" - -/* internal header */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "xxhash.h" -#include "include/buffer.h" -#include "common/cohort_lru.h" -#include "common/ceph_timer.h" -#include "rgw_common.h" -#include "rgw_user.h" -#include "rgw_lib.h" -#include "rgw_ldap.h" -#include "rgw_token.h" -#include "rgw_compression.h" - - -/* XXX - * ASSERT_H somehow not defined after all the above (which bring - * in common/debug.h [e.g., dout]) - */ -#include "include/assert.h" - - -#define RGW_RWXMODE (S_IRWXU | S_IRWXG | S_IRWXO) - -#define RGW_RWMODE (RGW_RWXMODE & \ - ~(S_IXUSR | S_IXGRP | S_IXOTH)) - - -namespace rgw { - - template - static inline void ignore(T &&) {} - - - namespace bi = boost::intrusive; - - class RGWLibFS; - class RGWFileHandle; - class RGWWriteRequest; - - static inline bool operator <(const struct timespec& lhs, - const struct timespec& rhs) { - if (lhs.tv_sec == rhs.tv_sec) - return lhs.tv_nsec < rhs.tv_nsec; - else - return lhs.tv_sec < rhs.tv_sec; - } - - static inline bool operator ==(const struct timespec& lhs, - const struct timespec& rhs) { - return ((lhs.tv_sec == rhs.tv_sec) && - (lhs.tv_nsec == rhs.tv_nsec)); - } - - /* - * XXX - * The current 64-bit, non-cryptographic hash used here is intended - * for prototyping only. - * - * However, the invariant being prototyped is that objects be - * identifiable by their hash components alone. We believe this can - * be legitimately implemented using 128-hash values for bucket and - * object components, together with a cluster-resident cryptographic - * key. Since an MD5 or SHA-1 key is 128 bits and the (fast), - * non-cryptographic CityHash128 hash algorithm takes a 128-bit seed, - * speculatively we could use that for the final hash computations. - */ - struct fh_key - { - rgw_fh_hk fh_hk; - uint32_t version; - - static constexpr uint64_t seed = 8675309; - - fh_key() : version(0) {} - - fh_key(const rgw_fh_hk& _hk) - : fh_hk(_hk), version(0) { - // nothing - } - - fh_key(const uint64_t bk, const uint64_t ok) - : version(0) { - fh_hk.bucket = bk; - fh_hk.object = ok; - } - - fh_key(const uint64_t bk, const char *_o) - : version(0) { - fh_hk.bucket = bk; - fh_hk.object = XXH64(_o, ::strlen(_o), seed); - } - - fh_key(const std::string& _b, const std::string& _o) - : version(0) { - fh_hk.bucket = XXH64(_b.c_str(), _o.length(), seed); - fh_hk.object = XXH64(_o.c_str(), _o.length(), seed); - } - - void encode(buffer::list& bl) const { - ENCODE_START(2, 1, bl); - ::encode(fh_hk.bucket, bl); - ::encode(fh_hk.object, bl); - ::encode((uint32_t)2, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::iterator& bl) { - DECODE_START(2, bl); - ::decode(fh_hk.bucket, bl); - ::decode(fh_hk.object, bl); - if (struct_v >= 2) { - ::decode(version, bl); - } - DECODE_FINISH(bl); - } - }; /* fh_key */ - - WRITE_CLASS_ENCODER(fh_key); - - inline bool operator<(const fh_key& lhs, const fh_key& rhs) - { - return ((lhs.fh_hk.bucket < rhs.fh_hk.bucket) || - ((lhs.fh_hk.bucket == rhs.fh_hk.bucket) && - (lhs.fh_hk.object < rhs.fh_hk.object))); - } - - inline bool operator>(const fh_key& lhs, const fh_key& rhs) - { - return (rhs < lhs); - } - - inline bool operator==(const fh_key& lhs, const fh_key& rhs) - { - return ((lhs.fh_hk.bucket == rhs.fh_hk.bucket) && - (lhs.fh_hk.object == rhs.fh_hk.object)); - } - - inline bool operator!=(const fh_key& lhs, const fh_key& rhs) - { - return !(lhs == rhs); - } - - inline bool operator<=(const fh_key& lhs, const fh_key& rhs) - { - return (lhs < rhs) || (lhs == rhs); - } - - using boost::variant; - using boost::container::flat_map; - - typedef std::tuple DecodeAttrsResult; - - class RGWFileHandle : public cohort::lru::Object - { - struct rgw_file_handle fh; - std::mutex mtx; - - RGWLibFS* fs; - RGWFileHandle* bucket; - RGWFileHandle* parent; - /* const */ std::string name; /* XXX file or bucket name */ - /* const */ fh_key fhk; - - using lock_guard = std::lock_guard; - using unique_lock = std::unique_lock; - - /* TODO: keeping just the last marker is sufficient for - * nfs-ganesha 2.4.5; in the near future, nfs-ganesha will - * be able to hint the name of the next dirent required, - * from which we can directly synthesize a RADOS marker. - * using marker_cache_t = flat_map; - */ - - struct State { - uint64_t dev; - uint64_t size; - uint64_t nlink; - uint32_t owner_uid; /* XXX need Unix attr */ - uint32_t owner_gid; /* XXX need Unix attr */ - mode_t unix_mode; - struct timespec ctime; - struct timespec mtime; - struct timespec atime; - uint32_t version; - State() : dev(0), size(0), nlink(1), owner_uid(0), owner_gid(0), - ctime{0,0}, mtime{0,0}, atime{0,0}, version(0) {} - } state; - - struct file { - RGWWriteRequest* write_req; - file() : write_req(nullptr) {} - ~file(); - }; - - struct directory { - - static constexpr uint32_t FLAG_NONE = 0x0000; - - uint32_t flags; - rgw_obj_key last_marker; - struct timespec last_readdir; - - directory() : flags(FLAG_NONE), last_readdir{0,0} {} - }; - - void clear_state(); - - boost::variant variant_type; - - uint16_t depth; - uint32_t flags; - - public: - const static std::string root_name; - - static constexpr uint16_t MAX_DEPTH = 256; - - static constexpr uint32_t FLAG_NONE = 0x0000; - static constexpr uint32_t FLAG_OPEN = 0x0001; - static constexpr uint32_t FLAG_ROOT = 0x0002; - static constexpr uint32_t FLAG_CREATE = 0x0004; - static constexpr uint32_t FLAG_CREATING = 0x0008; - static constexpr uint32_t FLAG_DIRECTORY = 0x0010; - static constexpr uint32_t FLAG_BUCKET = 0x0020; - static constexpr uint32_t FLAG_LOCK = 0x0040; - static constexpr uint32_t FLAG_DELETED = 0x0080; - static constexpr uint32_t FLAG_UNLINK_THIS = 0x0100; - static constexpr uint32_t FLAG_LOCKED = 0x0200; - static constexpr uint32_t FLAG_STATELESS_OPEN = 0x0400; - static constexpr uint32_t FLAG_EXACT_MATCH = 0x0800; - static constexpr uint32_t FLAG_MOUNT = 0x1000; - -#define CREATE_FLAGS(x) \ - ((x) & ~(RGWFileHandle::FLAG_CREATE|RGWFileHandle::FLAG_LOCK)) - - friend class RGWLibFS; - - private: - RGWFileHandle(RGWLibFS* _fs) - : fs(_fs), bucket(nullptr), parent(nullptr), variant_type{directory()}, - depth(0), flags(FLAG_NONE) - { - /* root */ - fh.fh_type = RGW_FS_TYPE_DIRECTORY; - variant_type = directory(); - /* stat */ - state.unix_mode = RGW_RWXMODE|S_IFDIR; - /* pointer to self */ - fh.fh_private = this; - } - - uint64_t init_fsid(std::string& uid) { - return XXH64(uid.c_str(), uid.length(), fh_key::seed); - } - - void init_rootfs(std::string& fsid, const std::string& object_name, - bool is_bucket) { - /* fh_key */ - fh.fh_hk.bucket = XXH64(fsid.c_str(), fsid.length(), fh_key::seed); - fh.fh_hk.object = XXH64(object_name.c_str(), object_name.length(), - fh_key::seed); - fhk = fh.fh_hk; - name = object_name; - - state.dev = init_fsid(fsid); - - if (is_bucket) { - flags |= RGWFileHandle::FLAG_BUCKET | RGWFileHandle::FLAG_MOUNT; - bucket = this; - depth = 1; - } else { - flags |= RGWFileHandle::FLAG_ROOT | RGWFileHandle::FLAG_MOUNT; - } - } - - public: - RGWFileHandle(RGWLibFS* _fs, RGWFileHandle* _parent, - const fh_key& _fhk, std::string& _name, uint32_t _flags) - : fs(_fs), bucket(nullptr), parent(_parent), name(std::move(_name)), - fhk(_fhk), flags(_flags) { - - if (parent->is_root()) { - fh.fh_type = RGW_FS_TYPE_DIRECTORY; - variant_type = directory(); - flags |= FLAG_BUCKET; - } else { - bucket = parent->is_bucket() ? parent - : parent->bucket; - if (flags & FLAG_DIRECTORY) { - fh.fh_type = RGW_FS_TYPE_DIRECTORY; - variant_type = directory(); - } else { - fh.fh_type = RGW_FS_TYPE_FILE; - variant_type = file(); - } - } - - depth = parent->depth + 1; - - /* save constant fhk */ - fh.fh_hk = fhk.fh_hk; /* XXX redundant in fh_hk */ - - /* inherits parent's fsid */ - state.dev = parent->state.dev; - - switch (fh.fh_type) { - case RGW_FS_TYPE_DIRECTORY: - state.unix_mode = RGW_RWXMODE|S_IFDIR; - break; - case RGW_FS_TYPE_FILE: - state.unix_mode = RGW_RWMODE|S_IFREG; - default: - break; - } - - /* pointer to self */ - fh.fh_private = this; - } - - const fh_key& get_key() const { - return fhk; - } - - directory* get_directory() { - return get(&variant_type); - } - - size_t get_size() const { return state.size; } - - const char* stype() { - return is_dir() ? "DIR" : "FILE"; - } - - uint16_t get_depth() const { return depth; } - - struct rgw_file_handle* get_fh() { return &fh; } - - RGWLibFS* get_fs() { return fs; } - - RGWFileHandle* get_parent() { return parent; } - - uint32_t get_owner_uid() const { return state.owner_uid; } - uint32_t get_owner_gid() const { return state.owner_gid; } - - struct timespec get_ctime() const { return state.ctime; } - struct timespec get_mtime() const { return state.mtime; } - - void create_stat(struct stat* st, uint32_t mask) { - if (mask & RGW_SETATTR_UID) - state.owner_uid = st->st_uid; - - if (mask & RGW_SETATTR_GID) - state.owner_gid = st->st_gid; - - if (mask & RGW_SETATTR_MODE) { - switch (fh.fh_type) { - case RGW_FS_TYPE_DIRECTORY: - state.unix_mode = st->st_mode|S_IFDIR; - break; - case RGW_FS_TYPE_FILE: - state.unix_mode = st->st_mode|S_IFREG; - default: - break; - } - } - - if (mask & RGW_SETATTR_ATIME) - state.atime = st->st_atim; - if (mask & RGW_SETATTR_MTIME) - state.mtime = st->st_mtim; - if (mask & RGW_SETATTR_CTIME) - state.ctime = st->st_ctim; - } - - int stat(struct stat* st) { - /* partial Unix attrs */ - memset(st, 0, sizeof(struct stat)); - st->st_dev = state.dev; - st->st_ino = fh.fh_hk.object; // XXX - - st->st_uid = state.owner_uid; - st->st_gid = state.owner_gid; - - st->st_mode = state.unix_mode; - -#ifdef HAVE_STAT_ST_MTIMESPEC_TV_NSEC - st->st_atimespec = state.atime; - st->st_mtimespec = state.mtime; - st->st_ctimespec = state.ctime; -#else - st->st_atim = state.atime; - st->st_mtim = state.mtime; - st->st_ctim = state.ctime; -#endif - - switch (fh.fh_type) { - case RGW_FS_TYPE_DIRECTORY: - st->st_nlink = state.nlink; - break; - case RGW_FS_TYPE_FILE: - st->st_nlink = 1; - st->st_blksize = 4096; - st->st_size = state.size; - st->st_blocks = (state.size) / 512; - default: - break; - } - - return 0; - } - - const std::string& bucket_name() const { - if (is_root()) - return root_name; - if (is_bucket()) - return name; - return bucket->object_name(); - } - - const std::string& object_name() const { return name; } - - std::string full_object_name(bool omit_bucket = false) const { - std::string path; - std::vector segments; - int reserve = 0; - const RGWFileHandle* tfh = this; - while (tfh && !tfh->is_root() && !(tfh->is_bucket() && omit_bucket)) { - segments.push_back(&tfh->object_name()); - reserve += (1 + tfh->object_name().length()); - tfh = tfh->parent; - } - bool first = true; - path.reserve(reserve); - for (auto& s : boost::adaptors::reverse(segments)) { - if (! first) - path += "/"; - else { - if (!omit_bucket && (path.front() != '/')) // pretty-print - path += "/"; - first = false; - } - path += *s; - } - return path; - } - - inline std::string relative_object_name() const { - return full_object_name(true /* omit_bucket */); - } - - inline std::string format_child_name(const std::string& cbasename, - bool is_dir) const { - std::string child_name{relative_object_name()}; - if ((child_name.size() > 0) && - (child_name.back() != '/')) - child_name += "/"; - child_name += cbasename; - if (is_dir) - child_name += "/"; - return child_name; - } - - inline std::string make_key_name(const char *name) const { - std::string key_name{full_object_name()}; - if (key_name.length() > 0) - key_name += "/"; - key_name += name; - return key_name; - } - - fh_key make_fhk(const std::string& name) const { - if (depth <= 1) - return fh_key(fhk.fh_hk.object, name.c_str()); - else { - std::string key_name = make_key_name(name.c_str()); - return fh_key(fhk.fh_hk.bucket, key_name.c_str()); - } - } - - void add_marker(uint64_t off, const rgw_obj_key& marker, - uint8_t obj_type) { - using std::get; - directory* d = get(&variant_type); - if (d) { - unique_lock guard(mtx); - d->last_marker = marker; - } - } - - const rgw_obj_key* find_marker(uint64_t off) const { - using std::get; - if (off > 0) { - const directory* d = get(&variant_type); - if (d ) { - return &d->last_marker; - } - } - return nullptr; - } - - int offset_of(const std::string& name, int64_t *offset, uint32_t flags) { - if (unlikely(! is_dir())) { - return -EINVAL; - } - *offset = XXH64(name.c_str(), name.length(), fh_key::seed); - return 0; - } - - bool is_open() const { return flags & FLAG_OPEN; } - bool is_root() const { return flags & FLAG_ROOT; } - bool is_mount() const { return flags & FLAG_MOUNT; } - bool is_bucket() const { return flags & FLAG_BUCKET; } - bool is_object() const { return !is_bucket(); } - bool is_file() const { return (fh.fh_type == RGW_FS_TYPE_FILE); } - bool is_dir() const { return (fh.fh_type == RGW_FS_TYPE_DIRECTORY); } - bool creating() const { return flags & FLAG_CREATING; } - bool deleted() const { return flags & FLAG_DELETED; } - bool stateless_open() const { return flags & FLAG_STATELESS_OPEN; } - bool has_children() const; - - int open(uint32_t gsh_flags) { - lock_guard guard(mtx); - if (! is_open()) { - if (gsh_flags & RGW_OPEN_FLAG_V3) { - flags |= FLAG_STATELESS_OPEN; - } - flags |= FLAG_OPEN; - return 0; - } - return -EPERM; - } - - typedef boost::variant readdir_offset; - - int readdir(rgw_readdir_cb rcb, void *cb_arg, readdir_offset offset, - bool *eof, uint32_t flags); - - int write(uint64_t off, size_t len, size_t *nbytes, void *buffer); - - int commit(uint64_t offset, uint64_t length, uint32_t flags) { - /* NFS3 and NFSv4 COMMIT implementation - * the current atomic update strategy doesn't actually permit - * clients to read-stable until either CLOSE (NFSv4+) or the - * expiration of the active write timer (NFS3). In the - * interim, the client may send an arbitrary number of COMMIT - * operations which must return a success result */ - return 0; - } - - int write_finish(uint32_t flags = FLAG_NONE); - int close(); - - void open_for_create() { - lock_guard guard(mtx); - flags |= FLAG_CREATING; - } - - void clear_creating() { - lock_guard guard(mtx); - flags &= ~FLAG_CREATING; - } - - void inc_nlink(const uint64_t n) { - state.nlink += n; - } - - void set_nlink(const uint64_t n) { - state.nlink = n; - } - - void set_size(const size_t size) { - state.size = size; - } - - void set_times(real_time t) { - state.ctime = real_clock::to_timespec(t); - state.mtime = state.ctime; - state.atime = state.ctime; - } - - void set_ctime(const struct timespec &ts) { - state.ctime = ts; - } - - void set_mtime(const struct timespec &ts) { - state.mtime = ts; - } - - void set_atime(const struct timespec &ts) { - state.atime = ts; - } - - void encode(buffer::list& bl) const { - ENCODE_START(2, 1, bl); - ::encode(uint32_t(fh.fh_type), bl); - ::encode(state.dev, bl); - ::encode(state.size, bl); - ::encode(state.nlink, bl); - ::encode(state.owner_uid, bl); - ::encode(state.owner_gid, bl); - ::encode(state.unix_mode, bl); - for (const auto& t : { state.ctime, state.mtime, state.atime }) { - ::encode(real_clock::from_timespec(t), bl); - } - ::encode((uint32_t)2, bl); - ENCODE_FINISH(bl); - } - - void decode(bufferlist::iterator& bl) { - DECODE_START(2, bl); - uint32_t fh_type; - ::decode(fh_type, bl); - assert(fh.fh_type == fh_type); - ::decode(state.dev, bl); - ::decode(state.size, bl); - ::decode(state.nlink, bl); - ::decode(state.owner_uid, bl); - ::decode(state.owner_gid, bl); - ::decode(state.unix_mode, bl); - ceph::real_time enc_time; - for (auto t : { &(state.ctime), &(state.mtime), &(state.atime) }) { - ::decode(enc_time, bl); - *t = real_clock::to_timespec(enc_time); - } - if (struct_v >= 2) { - ::decode(state.version, bl); - } - DECODE_FINISH(bl); - } - - void encode_attrs(ceph::buffer::list& ux_key1, - ceph::buffer::list& ux_attrs1); - - DecodeAttrsResult decode_attrs(const ceph::buffer::list* ux_key1, - const ceph::buffer::list* ux_attrs1); - - void invalidate(); - - bool reclaim() override; - - typedef cohort::lru::LRU FhLRU; - - struct FhLT - { - // for internal ordering - bool operator()(const RGWFileHandle& lhs, const RGWFileHandle& rhs) const - { return (lhs.get_key() < rhs.get_key()); } - - // for external search by fh_key - bool operator()(const fh_key& k, const RGWFileHandle& fh) const - { return k < fh.get_key(); } - - bool operator()(const RGWFileHandle& fh, const fh_key& k) const - { return fh.get_key() < k; } - }; - - struct FhEQ - { - bool operator()(const RGWFileHandle& lhs, const RGWFileHandle& rhs) const - { return (lhs.get_key() == rhs.get_key()); } - - bool operator()(const fh_key& k, const RGWFileHandle& fh) const - { return k == fh.get_key(); } - - bool operator()(const RGWFileHandle& fh, const fh_key& k) const - { return fh.get_key() == k; } - }; - - typedef bi::link_mode link_mode; /* XXX normal */ -#if defined(FHCACHE_AVL) - typedef bi::avl_set_member_hook tree_hook_type; -#else - /* RBT */ - typedef bi::set_member_hook tree_hook_type; -#endif - tree_hook_type fh_hook; - - typedef bi::member_hook< - RGWFileHandle, tree_hook_type, &RGWFileHandle::fh_hook> FhHook; - -#if defined(FHCACHE_AVL) - typedef bi::avltree, FhHook> FHTree; -#else - typedef bi::rbtree, FhHook> FhTree; -#endif - typedef cohort::lru::TreeX FHCache; - - ~RGWFileHandle() override; - - friend std::ostream& operator<<(std::ostream &os, - RGWFileHandle const &rgw_fh); - - class Factory : public cohort::lru::ObjectFactory - { - public: - RGWLibFS* fs; - RGWFileHandle* parent; - const fh_key& fhk; - std::string& name; - uint32_t flags; - - Factory() = delete; - - Factory(RGWLibFS* _fs, RGWFileHandle* _parent, - const fh_key& _fhk, std::string& _name, uint32_t _flags) - : fs(_fs), parent(_parent), fhk(_fhk), name(_name), - flags(_flags) {} - - void recycle (cohort::lru::Object* o) override { - /* re-use an existing object */ - o->~Object(); // call lru::Object virtual dtor - // placement new! - new (o) RGWFileHandle(fs, parent, fhk, name, flags); - } - - cohort::lru::Object* alloc() override { - return new RGWFileHandle(fs, parent, fhk, name, flags); - } - }; /* Factory */ - - }; /* RGWFileHandle */ - - WRITE_CLASS_ENCODER(RGWFileHandle); - - static inline RGWFileHandle* get_rgwfh(struct rgw_file_handle* fh) { - return static_cast(fh->fh_private); - } - - static inline enum rgw_fh_type fh_type_of(uint32_t flags) { - enum rgw_fh_type fh_type; - switch(flags & RGW_LOOKUP_TYPE_FLAGS) - { - case RGW_LOOKUP_FLAG_DIR: - fh_type = RGW_FS_TYPE_DIRECTORY; - break; - case RGW_LOOKUP_FLAG_FILE: - fh_type = RGW_FS_TYPE_FILE; - break; - default: - fh_type = RGW_FS_TYPE_NIL; - }; - return fh_type; - } - - typedef std::tuple LookupFHResult; - typedef std::tuple MkObjResult; - - class RGWLibFS - { - CephContext* cct; - struct rgw_fs fs{}; - RGWFileHandle root_fh; - rgw_fh_callback_t invalidate_cb; - void *invalidate_arg; - bool shutdown; - - mutable std::atomic refcnt; - - RGWFileHandle::FHCache fh_cache; - RGWFileHandle::FhLRU fh_lru; - - std::string uid; // should match user.user_id, iiuc - - RGWUserInfo user; - RGWAccessKey key; // XXXX acc_key - - static std::atomic fs_inst_counter; - - static uint32_t write_completion_interval_s; - - using lock_guard = std::lock_guard; - using unique_lock = std::unique_lock; - - struct event - { - enum class type : uint8_t { READDIR } ; - type t; - const fh_key fhk; - struct timespec ts; - event(type t, const fh_key& k, const struct timespec& ts) - : t(t), fhk(k), ts(ts) {} - }; - - friend std::ostream& operator<<(std::ostream &os, - RGWLibFS::event const &ev); - - using event_vector = /* boost::small_vector */ - std::vector; - - struct WriteCompletion - { - RGWFileHandle& rgw_fh; - - WriteCompletion(RGWFileHandle& _fh) : rgw_fh(_fh) { - rgw_fh.get_fs()->ref(&rgw_fh); - } - - void operator()() { - rgw_fh.close(); /* will finish in-progress write */ - rgw_fh.get_fs()->unref(&rgw_fh); - } - }; - - static ceph::timer write_timer; - - struct State { - std::mutex mtx; - std::atomic flags; - std::deque events; - - State() : flags(0) {} - - void push_event(const event& ev) { - events.push_back(ev); - } - } state; - - uint32_t new_inst() { - return ++fs_inst_counter; - } - - friend class RGWFileHandle; - friend class RGWLibProcess; - - public: - - static constexpr uint32_t FLAG_NONE = 0x0000; - static constexpr uint32_t FLAG_CLOSED = 0x0001; - - struct BucketStats { - size_t size; - size_t size_rounded; - real_time creation_time; - uint64_t num_entries; - }; - - RGWLibFS(CephContext* _cct, const char *_uid, const char *_user_id, - const char* _key, const char *root) - : cct(_cct), root_fh(this), invalidate_cb(nullptr), - invalidate_arg(nullptr), shutdown(false), refcnt(1), - fh_cache(cct->_conf->rgw_nfs_fhcache_partitions, - cct->_conf->rgw_nfs_fhcache_size), - fh_lru(cct->_conf->rgw_nfs_lru_lanes, - cct->_conf->rgw_nfs_lru_lane_hiwat), - uid(_uid), key(_user_id, _key) { - - if (!root || !strcmp(root, "/")) { - root_fh.init_rootfs(uid, RGWFileHandle::root_name, false); - } else { - root_fh.init_rootfs(uid, root, true); - } - - /* pointer to self */ - fs.fs_private = this; - - /* expose public root fh */ - fs.root_fh = root_fh.get_fh(); - - new_inst(); - } - - friend void intrusive_ptr_add_ref(const RGWLibFS* fs) { - fs->refcnt.fetch_add(1, std::memory_order_relaxed); - } - - friend void intrusive_ptr_release(const RGWLibFS* fs) { - if (fs->refcnt.fetch_sub(1, std::memory_order_release) == 0) { - std::atomic_thread_fence(std::memory_order_acquire); - delete fs; - } - } - - RGWLibFS* ref() { - intrusive_ptr_add_ref(this); - return this; - } - - inline void rele() { - intrusive_ptr_release(this); - } - - void stop() { shutdown = true; } - - void release_evict(RGWFileHandle* fh) { - /* remove from cache, releases sentinel ref */ - fh_cache.remove(fh->fh.fh_hk.object, fh, - RGWFileHandle::FHCache::FLAG_LOCK); - /* release call-path ref */ - (void) fh_lru.unref(fh, cohort::lru::FLAG_NONE); - } - - int authorize(RGWRados* store) { - int ret = rgw_get_user_info_by_access_key(store, key.id, user); - if (ret == 0) { - RGWAccessKey* key0 = user.get_key0(); - if (!key0 || - (key0->key != key.key)) - return -EINVAL; - if (user.suspended) - return -ERR_USER_SUSPENDED; - } else { - /* try external authenticators (ldap for now) */ - rgw::LDAPHelper* ldh = rgwlib.get_ldh(); /* !nullptr */ - RGWToken token; - /* boost filters and/or string_ref may throw on invalid input */ - try { - token = rgw::from_base64(key.id); - } catch(...) { - token = std::string(""); - } - if (token.valid() && (ldh->auth(token.id, token.key) == 0)) { - /* try to store user if it doesn't already exist */ - if (rgw_get_user_info_by_uid(store, token.id, user) < 0) { - int ret = rgw_store_user_info(store, user, NULL, NULL, real_time(), - true); - if (ret < 0) { - lsubdout(get_context(), rgw, 10) - << "NOTICE: failed to store new user's info: ret=" << ret - << dendl; - } - } - } /* auth success */ - } - return ret; - } /* authorize */ - - int register_invalidate(rgw_fh_callback_t cb, void *arg, uint32_t flags) { - invalidate_cb = cb; - invalidate_arg = arg; - return 0; - } - - /* find RGWFileHandle by id */ - LookupFHResult lookup_fh(const fh_key& fhk, - const uint32_t flags = RGWFileHandle::FLAG_NONE) { - using std::get; - - // cast int32_t(RGWFileHandle::FLAG_NONE) due to strictness of Clang - // the cast transfers a lvalue into a rvalue in the ctor - // check the commit message for the full details - LookupFHResult fhr { nullptr, uint32_t(RGWFileHandle::FLAG_NONE) }; - - RGWFileHandle::FHCache::Latch lat; - bool fh_locked = flags & RGWFileHandle::FLAG_LOCKED; - - retry: - RGWFileHandle* fh = - fh_cache.find_latch(fhk.fh_hk.object /* partition selector*/, - fhk /* key */, lat /* serializer */, - RGWFileHandle::FHCache::FLAG_LOCK); - /* LATCHED */ - if (fh) { - if (likely(! fh_locked)) - fh->mtx.lock(); // XXX !RAII because may-return-LOCKED - /* need initial ref from LRU (fast path) */ - if (! fh_lru.ref(fh, cohort::lru::FLAG_INITIAL)) { - lat.lock->unlock(); - if (likely(! fh_locked)) - fh->mtx.unlock(); - goto retry; /* !LATCHED */ - } - /* LATCHED, LOCKED */ - if (! (flags & RGWFileHandle::FLAG_LOCK)) - fh->mtx.unlock(); /* ! LOCKED */ - } - lat.lock->unlock(); /* !LATCHED */ - get<0>(fhr) = fh; - if (fh) { - lsubdout(get_context(), rgw, 17) - << __func__ << " 1 " << *fh - << dendl; - } - return fhr; - } /* lookup_fh(const fh_key&) */ - - /* find or create an RGWFileHandle */ - LookupFHResult lookup_fh(RGWFileHandle* parent, const char *name, - const uint32_t flags = RGWFileHandle::FLAG_NONE) { - using std::get; - - // cast int32_t(RGWFileHandle::FLAG_NONE) due to strictness of Clang - // the cast transfers a lvalue into a rvalue in the ctor - // check the commit message for the full details - LookupFHResult fhr { nullptr, uint32_t(RGWFileHandle::FLAG_NONE) }; - - /* mount is stale? */ - if (state.flags & FLAG_CLOSED) - return fhr; - - RGWFileHandle::FHCache::Latch lat; - bool fh_locked = flags & RGWFileHandle::FLAG_LOCKED; - - std::string obj_name{name}; - std::string key_name{parent->make_key_name(name)}; - - lsubdout(get_context(), rgw, 10) - << __func__ << " lookup called on " - << parent->object_name() << " for " << key_name - << " (" << obj_name << ")" - << dendl; - - fh_key fhk = parent->make_fhk(obj_name); - - retry: - RGWFileHandle* fh = - fh_cache.find_latch(fhk.fh_hk.object /* partition selector*/, - fhk /* key */, lat /* serializer */, - RGWFileHandle::FHCache::FLAG_LOCK); - /* LATCHED */ - if (fh) { - if (likely(! fh_locked)) - fh->mtx.lock(); // XXX !RAII because may-return-LOCKED - if (fh->flags & RGWFileHandle::FLAG_DELETED) { - /* for now, delay briefly and retry */ - lat.lock->unlock(); - if (likely(! fh_locked)) - fh->mtx.unlock(); - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - goto retry; /* !LATCHED */ - } - /* need initial ref from LRU (fast path) */ - if (! fh_lru.ref(fh, cohort::lru::FLAG_INITIAL)) { - lat.lock->unlock(); - if (likely(! fh_locked)) - fh->mtx.unlock(); - goto retry; /* !LATCHED */ - } - /* LATCHED, LOCKED */ - if (! (flags & RGWFileHandle::FLAG_LOCK)) - if (likely(! fh_locked)) - fh->mtx.unlock(); /* ! LOCKED */ - } else { - /* make or re-use handle */ - RGWFileHandle::Factory prototype(this, parent, fhk, - obj_name, CREATE_FLAGS(flags)); - fh = static_cast( - fh_lru.insert(&prototype, - cohort::lru::Edge::MRU, - cohort::lru::FLAG_INITIAL)); - if (fh) { - /* lock fh (LATCHED) */ - if (flags & RGWFileHandle::FLAG_LOCK) - fh->mtx.lock(); - /* inserts, releasing latch */ - fh_cache.insert_latched(fh, lat, RGWFileHandle::FHCache::FLAG_UNLOCK); - get<1>(fhr) |= RGWFileHandle::FLAG_CREATE; - /* ref parent (non-initial ref cannot fail on valid object) */ - if (! parent->is_mount()) { - (void) fh_lru.ref(parent, cohort::lru::FLAG_NONE); - } - goto out; /* !LATCHED */ - } else { - lat.lock->unlock(); - goto retry; /* !LATCHED */ - } - } - lat.lock->unlock(); /* !LATCHED */ - out: - get<0>(fhr) = fh; - if (fh) { - lsubdout(get_context(), rgw, 17) - << __func__ << " 2 " << *fh - << dendl; - } - return fhr; - } /* lookup_fh(RGWFileHandle*, const char *, const uint32_t) */ - - inline void unref(RGWFileHandle* fh) { - if (likely(! fh->is_mount())) { - (void) fh_lru.unref(fh, cohort::lru::FLAG_NONE); - } - } - - inline RGWFileHandle* ref(RGWFileHandle* fh) { - if (likely(! fh->is_mount())) { - fh_lru.ref(fh, cohort::lru::FLAG_NONE); - } - return fh; - } - - int getattr(RGWFileHandle* rgw_fh, struct stat* st); - - int setattr(RGWFileHandle* rgw_fh, struct stat* st, uint32_t mask, - uint32_t flags); - - void update_fh(RGWFileHandle *rgw_fh); - - LookupFHResult stat_bucket(RGWFileHandle* parent, const char *path, - RGWLibFS::BucketStats& bs, - uint32_t flags); - - LookupFHResult stat_leaf(RGWFileHandle* parent, const char *path, - enum rgw_fh_type type = RGW_FS_TYPE_NIL, - uint32_t flags = RGWFileHandle::FLAG_NONE); - - int read(RGWFileHandle* rgw_fh, uint64_t offset, size_t length, - size_t* bytes_read, void* buffer, uint32_t flags); - - int rename(RGWFileHandle* old_fh, RGWFileHandle* new_fh, - const char *old_name, const char *new_name); - - MkObjResult create(RGWFileHandle* parent, const char *name, struct stat *st, - uint32_t mask, uint32_t flags); - - MkObjResult mkdir(RGWFileHandle* parent, const char *name, struct stat *st, - uint32_t mask, uint32_t flags); - - int unlink(RGWFileHandle* rgw_fh, const char *name, - uint32_t flags = FLAG_NONE); - - /* find existing RGWFileHandle */ - RGWFileHandle* lookup_handle(struct rgw_fh_hk fh_hk) { - - if (state.flags & FLAG_CLOSED) - return nullptr; - - RGWFileHandle::FHCache::Latch lat; - fh_key fhk(fh_hk); - - retry: - RGWFileHandle* fh = - fh_cache.find_latch(fhk.fh_hk.object /* partition selector*/, - fhk /* key */, lat /* serializer */, - RGWFileHandle::FHCache::FLAG_LOCK); - /* LATCHED */ - if (! fh) { - lsubdout(get_context(), rgw, 0) - << __func__ << " handle lookup failed <" - << fhk.fh_hk.bucket << "," << fhk.fh_hk.object << ">" - << "(need persistent handles)" - << dendl; - goto out; - } - fh->mtx.lock(); - if (fh->flags & RGWFileHandle::FLAG_DELETED) { - /* for now, delay briefly and retry */ - lat.lock->unlock(); - fh->mtx.unlock(); /* !LOCKED */ - std::this_thread::sleep_for(std::chrono::milliseconds(20)); - goto retry; /* !LATCHED */ - } - if (! fh_lru.ref(fh, cohort::lru::FLAG_INITIAL)) { - lat.lock->unlock(); - fh->mtx.unlock(); - goto retry; /* !LATCHED */ - } - /* LATCHED */ - fh->mtx.unlock(); /* !LOCKED */ - out: - lat.lock->unlock(); /* !LATCHED */ - - /* special case: lookup root_fh */ - if (! fh) { - if (unlikely(fh_hk == root_fh.fh.fh_hk)) { - fh = &root_fh; - } - } - - return fh; - } - - CephContext* get_context() { - return cct; - } - - struct rgw_fs* get_fs() { return &fs; } - - uint64_t get_fsid() { return root_fh.state.dev; } - - RGWUserInfo* get_user() { return &user; } - - void close(); - void gc(); - }; /* RGWLibFS */ - -static inline std::string make_uri(const std::string& bucket_name, - const std::string& object_name) { - std::string uri("/"); - uri.reserve(bucket_name.length() + object_name.length() + 2); - uri += bucket_name; - uri += "/"; - uri += object_name; - return uri; -} - -/* - read directory content (buckets) -*/ - -class RGWListBucketsRequest : public RGWLibRequest, - public RGWListBuckets /* RGWOp */ -{ -public: - RGWFileHandle* rgw_fh; - RGWFileHandle::readdir_offset offset; - void* cb_arg; - rgw_readdir_cb rcb; - uint64_t* ioff; - size_t ix; - uint32_t d_count; - - RGWListBucketsRequest(CephContext* _cct, RGWUserInfo *_user, - RGWFileHandle* _rgw_fh, rgw_readdir_cb _rcb, - void* _cb_arg, RGWFileHandle::readdir_offset& _offset) - : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), offset(_offset), - cb_arg(_cb_arg), rcb(_rcb), ioff(nullptr), ix(0), d_count(0) { - - using boost::get; - - if (unlikely(!! get(&offset))) { - ioff = get(offset); - const auto& mk = rgw_fh->find_marker(*ioff); - if (mk) { - marker = mk->name; - } - } else { - const char* mk = get(offset); - if (mk) { - marker = mk; - } - } - op = this; - } - - bool only_bucket() override { return false; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - struct req_state* s = get_state(); - s->info.method = "GET"; - s->op = OP_GET; - - /* XXX derp derp derp */ - s->relative_uri = "/"; - s->info.request_uri = "/"; // XXX - s->info.effective_uri = "/"; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - return 0; - } - - int get_params() override { - limit = -1; /* no limit */ - return 0; - } - - void send_response_begin(bool has_buckets) override { - sent_data = true; - } - - void send_response_data(RGWUserBuckets& buckets) override { - if (!sent_data) - return; - map& m = buckets.get_buckets(); - for (const auto& iter : m) { - boost::string_ref marker{iter.first}; - const RGWBucketEnt& ent = iter.second; - if (! this->operator()(ent.bucket.name, marker)) { - /* caller cannot accept more */ - lsubdout(cct, rgw, 5) << "ListBuckets rcb failed" - << " dirent=" << ent.bucket.name - << " call count=" << ix - << dendl; - return; - } - ++ix; - } - } /* send_response_data */ - - void send_response_end() override { - // do nothing - } - - int operator()(const boost::string_ref& name, - const boost::string_ref& marker) { - uint64_t off = XXH64(name.data(), name.length(), fh_key::seed); - if (!! ioff) { - *ioff = off; - } - /* update traversal cache */ - rgw_fh->add_marker(off, rgw_obj_key{marker.data(), ""}, - RGW_FS_TYPE_DIRECTORY); - ++d_count; - return rcb(name.data(), cb_arg, off, RGW_LOOKUP_FLAG_DIR); - } - - bool eof() { - lsubdout(cct, rgw, 15) << "READDIR offset: " << offset - << " is_truncated: " << is_truncated - << dendl; - return !is_truncated; - } - -}; /* RGWListBucketsRequest */ - -/* - read directory content (bucket objects) -*/ - -class RGWReaddirRequest : public RGWLibRequest, - public RGWListBucket /* RGWOp */ -{ -public: - RGWFileHandle* rgw_fh; - RGWFileHandle::readdir_offset offset; - void* cb_arg; - rgw_readdir_cb rcb; - uint64_t* ioff; - size_t ix; - uint32_t d_count; - - RGWReaddirRequest(CephContext* _cct, RGWUserInfo *_user, - RGWFileHandle* _rgw_fh, rgw_readdir_cb _rcb, - void* _cb_arg, RGWFileHandle::readdir_offset& _offset) - : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), offset(_offset), - cb_arg(_cb_arg), rcb(_rcb), ioff(nullptr), ix(0), d_count(0) { - - using boost::get; - - if (unlikely(!! get(&offset))) { - ioff = get(offset); - const auto& mk = rgw_fh->find_marker(*ioff); - if (mk) { - marker = *mk; - } - } else { - const char* mk = get(offset); - if (mk) { - std::string tmark{rgw_fh->relative_object_name()}; - tmark += "/"; - tmark += mk; - marker = rgw_obj_key{std::move(tmark), "", ""}; - } - } - - default_max = 1000; // XXX was being omitted - op = this; - } - - bool only_bucket() override { return true; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - struct req_state* s = get_state(); - s->info.method = "GET"; - s->op = OP_GET; - - /* XXX derp derp derp */ - std::string uri = "/" + rgw_fh->bucket_name() + "/"; - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - prefix = rgw_fh->relative_object_name(); - if (prefix.length() > 0) - prefix += "/"; - delimiter = '/'; - - return 0; - } - - int operator()(const boost::string_ref name, const rgw_obj_key& marker, - uint8_t type) { - - assert(name.length() > 0); // XXX - - /* hash offset of name in parent (short name) for NFS readdir cookie */ - uint64_t off = XXH64(name.data(), name.length(), fh_key::seed); - if (unlikely(!! ioff)) { - *ioff = off; - } - /* update traversal cache */ - rgw_fh->add_marker(off, marker, type); - ++d_count; - return rcb(name.data(), cb_arg, off, - (type == RGW_FS_TYPE_DIRECTORY) ? - RGW_LOOKUP_FLAG_DIR : - RGW_LOOKUP_FLAG_FILE); - } - - int get_params() override { - max = default_max; - return 0; - } - - void send_response() override { - struct req_state* s = get_state(); - for (const auto& iter : objs) { - - boost::string_ref sref {iter.key.name}; - - lsubdout(cct, rgw, 15) << "readdir objects prefix: " << prefix - << " obj: " << sref << dendl; - - size_t last_del = sref.find_last_of('/'); - if (last_del != string::npos) - sref.remove_prefix(last_del+1); - - /* leaf directory? */ - if (sref.empty()) - continue; - - lsubdout(cct, rgw, 15) << "RGWReaddirRequest " - << __func__ << " " - << "list uri=" << s->relative_uri << " " - << " prefix=" << prefix << " " - << " obj path=" << iter.key.name - << " (" << sref << ")" << "" - << dendl; - - if(! this->operator()(sref, next_marker, RGW_FS_TYPE_FILE)) { - /* caller cannot accept more */ - lsubdout(cct, rgw, 5) << "readdir rcb failed" - << " dirent=" << sref.data() - << " call count=" << ix - << dendl; - return; - } - ++ix; - } - for (auto& iter : common_prefixes) { - - lsubdout(cct, rgw, 15) << "readdir common prefixes prefix: " << prefix - << " iter first: " << iter.first - << " iter second: " << iter.second - << dendl; - - /* XXX aieee--I have seen this case! */ - if (iter.first == "/") - continue; - - /* it's safest to modify the element in place--a suffix-modifying - * string_ref operation is problematic since ULP rgw_file callers - * will ultimately need a c-string */ - if (iter.first.back() == '/') - const_cast(iter.first).pop_back(); - - boost::string_ref sref{iter.first}; - - size_t last_del = sref.find_last_of('/'); - if (last_del != string::npos) - sref.remove_prefix(last_del+1); - - lsubdout(cct, rgw, 15) << "RGWReaddirRequest " - << __func__ << " " - << "list uri=" << s->relative_uri << " " - << " prefix=" << prefix << " " - << " cpref=" << sref - << dendl; - - this->operator()(sref, next_marker, RGW_FS_TYPE_DIRECTORY); - ++ix; - } - } - - virtual void send_versioned_response() { - send_response(); - } - - bool eof() { - lsubdout(cct, rgw, 15) << "READDIR offset: " << offset - << " next marker: " << next_marker - << " is_truncated: " << is_truncated - << dendl; - return !is_truncated; - } - -}; /* RGWReaddirRequest */ - -/* - dir has-children predicate (bucket objects) -*/ - -class RGWRMdirCheck : public RGWLibRequest, - public RGWListBucket /* RGWOp */ -{ -public: - const RGWFileHandle* rgw_fh; - bool valid; - bool has_children; - - RGWRMdirCheck (CephContext* _cct, RGWUserInfo *_user, - const RGWFileHandle* _rgw_fh) - : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), valid(false), - has_children(false) { - default_max = 2; - op = this; - } - - bool only_bucket() override { return true; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - struct req_state* s = get_state(); - s->info.method = "GET"; - s->op = OP_GET; - - std::string uri = "/" + rgw_fh->bucket_name() + "/"; - s->relative_uri = uri; - s->info.request_uri = uri; - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - s->user = user; - - prefix = rgw_fh->relative_object_name(); - if (prefix.length() > 0) - prefix += "/"; - delimiter = '/'; - - return 0; - } - - int get_params() override { - max = default_max; - return 0; - } - - void send_response() override { - valid = true; - if ((objs.size() > 1) || - (! objs.empty() && - (objs.front().key.name != prefix))) { - has_children = true; - return; - } - for (auto& iter : common_prefixes) { - /* readdir never produces a name for this case */ - if (iter.first == "/") - continue; - has_children = true; - break; - } - } - - virtual void send_versioned_response() { - send_response(); - } - -}; /* RGWRMdirCheck */ - -/* - create bucket -*/ - -class RGWCreateBucketRequest : public RGWLibRequest, - public RGWCreateBucket /* RGWOp */ -{ -public: - const std::string& bucket_name; - - RGWCreateBucketRequest(CephContext* _cct, RGWUserInfo *_user, - std::string& _bname) - : RGWLibRequest(_cct, _user), bucket_name(_bname) { - op = this; - } - - bool only_bucket() override { return false; } - - int read_permissions(RGWOp* op_obj) override { - /* we ARE a 'create bucket' request (cf. rgw_rest.cc, ll. 1305-6) */ - return 0; - } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "PUT"; - s->op = OP_PUT; - - string uri = "/" + bucket_name; - /* XXX derp derp derp */ - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - return 0; - } - - int get_params() override { - struct req_state* s = get_state(); - RGWAccessControlPolicy_S3 s3policy(s->cct); - /* we don't have (any) headers, so just create canned ACLs */ - int ret = s3policy.create_canned(s->owner, s->bucket_owner, s->canned_acl); - policy = s3policy; - return ret; - } - - void send_response() override { - /* TODO: something (maybe) */ - } -}; /* RGWCreateBucketRequest */ - -/* - delete bucket -*/ - -class RGWDeleteBucketRequest : public RGWLibRequest, - public RGWDeleteBucket /* RGWOp */ -{ -public: - const std::string& bucket_name; - - RGWDeleteBucketRequest(CephContext* _cct, RGWUserInfo *_user, - std::string& _bname) - : RGWLibRequest(_cct, _user), bucket_name(_bname) { - op = this; - } - - bool only_bucket() override { return true; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "DELETE"; - s->op = OP_DELETE; - - string uri = "/" + bucket_name; - /* XXX derp derp derp */ - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - return 0; - } - - void send_response() override {} - -}; /* RGWDeleteBucketRequest */ - -/* - put object -*/ -class RGWPutObjRequest : public RGWLibRequest, - public RGWPutObj /* RGWOp */ -{ -public: - const std::string& bucket_name; - const std::string& obj_name; - buffer::list& bl; /* XXX */ - size_t bytes_written; - - RGWPutObjRequest(CephContext* _cct, RGWUserInfo *_user, - const std::string& _bname, const std::string& _oname, - buffer::list& _bl) - : RGWLibRequest(_cct, _user), bucket_name(_bname), obj_name(_oname), - bl(_bl), bytes_written(0) { - op = this; - } - - bool only_bucket() override { return true; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - - int rc = valid_s3_object_name(obj_name); - if (rc != 0) - return rc; - - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "PUT"; - s->op = OP_PUT; - - /* XXX derp derp derp */ - std::string uri = make_uri(bucket_name, obj_name); - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - /* XXX required in RGWOp::execute() */ - s->content_length = bl.length(); - - // woo - s->user = user; - - return 0; - } - - int get_params() override { - struct req_state* s = get_state(); - RGWAccessControlPolicy_S3 s3policy(s->cct); - /* we don't have (any) headers, so just create canned ACLs */ - int ret = s3policy.create_canned(s->owner, s->bucket_owner, s->canned_acl); - policy = s3policy; - return ret; - } - - int get_data(buffer::list& _bl) override { - /* XXX for now, use sharing semantics */ - _bl.claim(bl); - uint32_t len = _bl.length(); - bytes_written += len; - return len; - } - - void send_response() override {} - - int verify_params() override { - if (bl.length() > cct->_conf->rgw_max_put_size) - return -ERR_TOO_LARGE; - return 0; - } - -}; /* RGWPutObjRequest */ - -/* - get object -*/ - -class RGWReadRequest : public RGWLibRequest, - public RGWGetObj /* RGWOp */ -{ -public: - RGWFileHandle* rgw_fh; - void *ulp_buffer; - size_t nread; - size_t read_resid; /* initialize to len, <= sizeof(ulp_buffer) */ - bool do_hexdump = false; - - RGWReadRequest(CephContext* _cct, RGWUserInfo *_user, - RGWFileHandle* _rgw_fh, uint64_t off, uint64_t len, - void *_ulp_buffer) - : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), ulp_buffer(_ulp_buffer), - nread(0), read_resid(len) { - op = this; - - /* fixup RGWGetObj (already know range parameters) */ - RGWGetObj::range_parsed = true; - RGWGetObj::get_data = true; // XXX - RGWGetObj::partial_content = true; - RGWGetObj::ofs = off; - RGWGetObj::end = off + len; - } - - bool only_bucket() override { return false; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "GET"; - s->op = OP_GET; - - /* XXX derp derp derp */ - s->relative_uri = make_uri(rgw_fh->bucket_name(), - rgw_fh->relative_object_name()); - s->info.request_uri = s->relative_uri; // XXX - s->info.effective_uri = s->relative_uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - return 0; - } - - int get_params() override { - return 0; - } - - int send_response_data(ceph::buffer::list& bl, off_t bl_off, - off_t bl_len) override { - size_t bytes; - for (auto& bp : bl.buffers()) { - /* if for some reason bl_off indicates the start-of-data is not at - * the current buffer::ptr, skip it and account */ - if (bl_off > bp.length()) { - bl_off -= bp.length(); - continue; - } - /* read no more than read_resid */ - bytes = std::min(read_resid, size_t(bp.length()-bl_off)); - memcpy(static_cast(ulp_buffer)+nread, bp.c_str()+bl_off, bytes); - read_resid -= bytes; /* reduce read_resid by bytes read */ - nread += bytes; - bl_off = 0; - /* stop if we have no residual ulp_buffer */ - if (! read_resid) - break; - } - return 0; - } - - int send_response_data_error() override { - /* S3 implementation just sends nothing--there is no side effect - * to simulate here */ - return 0; - } - -}; /* RGWReadRequest */ - -/* - delete object -*/ - -class RGWDeleteObjRequest : public RGWLibRequest, - public RGWDeleteObj /* RGWOp */ -{ -public: - const std::string& bucket_name; - const std::string& obj_name; - - RGWDeleteObjRequest(CephContext* _cct, RGWUserInfo *_user, - const std::string& _bname, const std::string& _oname) - : RGWLibRequest(_cct, _user), bucket_name(_bname), obj_name(_oname) { - op = this; - } - - bool only_bucket() override { return true; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "DELETE"; - s->op = OP_DELETE; - - /* XXX derp derp derp */ - std::string uri = make_uri(bucket_name, obj_name); - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - return 0; - } - - void send_response() override {} - -}; /* RGWDeleteObjRequest */ - -class RGWStatObjRequest : public RGWLibRequest, - public RGWGetObj /* RGWOp */ -{ -public: - const std::string& bucket_name; - const std::string& obj_name; - uint64_t _size; - uint32_t flags; - - static constexpr uint32_t FLAG_NONE = 0x000; - - RGWStatObjRequest(CephContext* _cct, RGWUserInfo *_user, - const std::string& _bname, const std::string& _oname, - uint32_t _flags) - : RGWLibRequest(_cct, _user), bucket_name(_bname), obj_name(_oname), - _size(0), flags(_flags) { - op = this; - - /* fixup RGWGetObj (already know range parameters) */ - RGWGetObj::range_parsed = true; - RGWGetObj::get_data = false; // XXX - RGWGetObj::partial_content = true; - RGWGetObj::ofs = 0; - RGWGetObj::end = UINT64_MAX; - } - - const string name() override { return "stat_obj"; } - RGWOpType get_type() override { return RGW_OP_STAT_OBJ; } - - real_time get_mtime() const { - return lastmod; - } - - /* attributes */ - uint64_t get_size() { return _size; } - real_time ctime() { return mod_time; } // XXX - real_time mtime() { return mod_time; } - std::map& get_attrs() { return attrs; } - - buffer::list* get_attr(const std::string& k) { - auto iter = attrs.find(k); - return (iter != attrs.end()) ? &(iter->second) : nullptr; - } - - bool only_bucket() override { return false; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "GET"; - s->op = OP_GET; - - /* XXX derp derp derp */ - s->relative_uri = make_uri(bucket_name, obj_name); - s->info.request_uri = s->relative_uri; // XXX - s->info.effective_uri = s->relative_uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - return 0; - } - - int get_params() override { - return 0; - } - - int send_response_data(ceph::buffer::list& _bl, off_t s_off, - off_t e_off) override { - /* NOP */ - /* XXX save attrs? */ - return 0; - } - - int send_response_data_error() override { - /* NOP */ - return 0; - } - - void execute() override { - RGWGetObj::execute(); - _size = get_state()->obj_size; - } - -}; /* RGWStatObjRequest */ - -class RGWStatBucketRequest : public RGWLibRequest, - public RGWStatBucket /* RGWOp */ -{ -public: - std::string uri; - std::map attrs; - RGWLibFS::BucketStats& bs; - - RGWStatBucketRequest(CephContext* _cct, RGWUserInfo *_user, - const std::string& _path, - RGWLibFS::BucketStats& _stats) - : RGWLibRequest(_cct, _user), bs(_stats) { - uri = "/" + _path; - op = this; - } - - buffer::list* get_attr(const std::string& k) { - auto iter = attrs.find(k); - return (iter != attrs.end()) ? &(iter->second) : nullptr; - } - - real_time get_ctime() const { - return bucket.creation_time; - } - - bool only_bucket() override { return false; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "GET"; - s->op = OP_GET; - - /* XXX derp derp derp */ - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - return 0; - } - - virtual int get_params() { - return 0; - } - - void send_response() override { - bucket.creation_time = get_state()->bucket_info.creation_time; - bs.size = bucket.size; - bs.size_rounded = bucket.size_rounded; - bs.creation_time = bucket.creation_time; - bs.num_entries = bucket.count; - std::swap(attrs, get_state()->bucket_attrs); - } - - bool matched() { - return (bucket.bucket.name.length() > 0); - } - -}; /* RGWStatBucketRequest */ - -class RGWStatLeafRequest : public RGWLibRequest, - public RGWListBucket /* RGWOp */ -{ -public: - RGWFileHandle* rgw_fh; - std::string path; - bool matched; - bool is_dir; - bool exact_matched; - - RGWStatLeafRequest(CephContext* _cct, RGWUserInfo *_user, - RGWFileHandle* _rgw_fh, const std::string& _path) - : RGWLibRequest(_cct, _user), rgw_fh(_rgw_fh), path(_path), - matched(false), is_dir(false), exact_matched(false) { - default_max = 1000; // logical max {"foo", "foo/"} - op = this; - } - - bool only_bucket() override { return true; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "GET"; - s->op = OP_GET; - - /* XXX derp derp derp */ - std::string uri = "/" + rgw_fh->bucket_name() + "/"; - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - prefix = rgw_fh->relative_object_name(); - if (prefix.length() > 0) - prefix += "/"; - prefix += path; - delimiter = '/'; - - return 0; - } - - int get_params() override { - max = default_max; - return 0; - } - - void send_response() override { - struct req_state* s = get_state(); - // try objects - for (const auto& iter : objs) { - auto& name = iter.key.name; - lsubdout(cct, rgw, 15) << "RGWStatLeafRequest " - << __func__ << " " - << "list uri=" << s->relative_uri << " " - << " prefix=" << prefix << " " - << " obj path=" << name << "" - << " target = " << path << "" - << dendl; - /* XXX is there a missing match-dir case (trailing '/')? */ - matched = true; - if (name == path) - exact_matched = true; - return; - } - // try prefixes - for (auto& iter : common_prefixes) { - auto& name = iter.first; - lsubdout(cct, rgw, 15) << "RGWStatLeafRequest " - << __func__ << " " - << "list uri=" << s->relative_uri << " " - << " prefix=" << prefix << " " - << " pref path=" << name << " (not chomped)" - << " target = " << path << "" - << dendl; - matched = true; - is_dir = true; - break; - } - } - - virtual void send_versioned_response() { - send_response(); - } -}; /* RGWStatLeafRequest */ - -/* - put object -*/ - -class RGWWriteRequest : public RGWLibContinuedReq, - public RGWPutObj /* RGWOp */ -{ -public: - const std::string& bucket_name; - const std::string& obj_name; - RGWFileHandle* rgw_fh; - RGWPutObjProcessor* processor; - RGWPutObjDataProcessor* filter; - boost::optional compressor; - CompressorRef plugin; - buffer::list data; - uint64_t timer_id; - MD5 hash; - off_t real_ofs; - size_t bytes_written; - bool multipart; - bool eio; - - RGWWriteRequest(CephContext* _cct, RGWUserInfo *_user, RGWFileHandle* _fh, - const std::string& _bname, const std::string& _oname) - : RGWLibContinuedReq(_cct, _user), bucket_name(_bname), obj_name(_oname), - rgw_fh(_fh), processor(nullptr), filter(nullptr), real_ofs(0), - bytes_written(0), multipart(false), eio(false) { - - int ret = header_init(); - if (ret == 0) { - ret = init_from_header(get_state()); - } - op = this; - } - - bool only_bucket() override { return true; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "PUT"; - s->op = OP_PUT; - - /* XXX derp derp derp */ - std::string uri = make_uri(bucket_name, obj_name); - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - return 0; - } - - RGWPutObjProcessor *select_processor(RGWObjectCtx& obj_ctx, - bool *is_multipart) override { - struct req_state* s = get_state(); - uint64_t part_size = s->cct->_conf->rgw_obj_stripe_size; - RGWPutObjProcessor_Atomic *processor = - new RGWPutObjProcessor_Atomic(obj_ctx, s->bucket_info, s->bucket, - s->object.name, part_size, s->req_id, - s->bucket_info.versioning_enabled()); - processor->set_olh_epoch(olh_epoch); - processor->set_version_id(version_id); - return processor; - } - - int get_params() override { - struct req_state* s = get_state(); - RGWAccessControlPolicy_S3 s3policy(s->cct); - /* we don't have (any) headers, so just create canned ACLs */ - int ret = s3policy.create_canned(s->owner, s->bucket_owner, s->canned_acl); - policy = s3policy; - return ret; - } - - int get_data(buffer::list& _bl) override { - /* XXX for now, use sharing semantics */ - uint32_t len = data.length(); - _bl.claim(data); - bytes_written += len; - return len; - } - - void put_data(off_t off, buffer::list& _bl) { - if (off != real_ofs) { - eio = true; - } - data.claim(_bl); - real_ofs += data.length(); - ofs = off; /* consumed in exec_continue() */ - } - - int exec_start() override; - int exec_continue() override; - int exec_finish() override; - - void send_response() override {} - - int verify_params() override { - return 0; - } -}; /* RGWWriteRequest */ - -/* - copy object -*/ -class RGWCopyObjRequest : public RGWLibRequest, - public RGWCopyObj /* RGWOp */ -{ -public: - RGWFileHandle* src_parent; - RGWFileHandle* dst_parent; - const std::string& src_name; - const std::string& dst_name; - - RGWCopyObjRequest(CephContext* _cct, RGWUserInfo *_user, - RGWFileHandle* _src_parent, RGWFileHandle* _dst_parent, - const std::string& _src_name, const std::string& _dst_name) - : RGWLibRequest(_cct, _user), src_parent(_src_parent), - dst_parent(_dst_parent), src_name(_src_name), dst_name(_dst_name) { - /* all requests have this */ - op = this; - - /* allow this request to replace selected attrs */ - attrs_mod = RGWRados::ATTRSMOD_MERGE; - } - - bool only_bucket() override { return true; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "PUT"; // XXX check - s->op = OP_PUT; - - src_bucket_name = src_parent->bucket_name(); - // need s->src_bucket_name? - src_object.name = src_parent->format_child_name(src_name, false); - // need s->src_object? - - dest_bucket_name = dst_parent->bucket_name(); - // need s->bucket.name? - dest_object = dst_parent->format_child_name(dst_name, false); - // need s->object_name? - - int rc = valid_s3_object_name(dest_object); - if (rc != 0) - return rc; - - /* XXX and fixup key attr (could optimize w/string ref and - * dest_object) */ - buffer::list ux_key; - fh_key fhk = dst_parent->make_fhk(dst_name); - rgw::encode(fhk, ux_key); - emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key)); - -#if 0 /* XXX needed? */ - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ -#endif - - // woo - s->user = user; - - return 0; - } - - int get_params() override { - struct req_state* s = get_state(); - RGWAccessControlPolicy_S3 s3policy(s->cct); - /* we don't have (any) headers, so just create canned ACLs */ - int ret = s3policy.create_canned(s->owner, s->bucket_owner, s->canned_acl); - dest_policy = s3policy; - return ret; - } - - void send_response() override {} - void send_partial_response(off_t ofs) override {} - -}; /* RGWCopyObjRequest */ - -class RGWSetAttrsRequest : public RGWLibRequest, - public RGWSetAttrs /* RGWOp */ -{ -public: - const std::string& bucket_name; - const std::string& obj_name; - - RGWSetAttrsRequest(CephContext* _cct, RGWUserInfo *_user, - const std::string& _bname, const std::string& _oname) - : RGWLibRequest(_cct, _user), bucket_name(_bname), obj_name(_oname) { - op = this; - } - - bool only_bucket() override { return false; } - - int op_init() override { - // assign store, s, and dialect_handler - RGWObjectCtx* rados_ctx - = static_cast(get_state()->obj_ctx); - // framework promises to call op_init after parent init - assert(rados_ctx); - RGWOp::init(rados_ctx->store, get_state(), this); - op = this; // assign self as op: REQUIRED - return 0; - } - - int header_init() override { - - struct req_state* s = get_state(); - s->info.method = "PUT"; - s->op = OP_PUT; - - /* XXX derp derp derp */ - std::string uri = make_uri(bucket_name, obj_name); - s->relative_uri = uri; - s->info.request_uri = uri; // XXX - s->info.effective_uri = uri; - s->info.request_params = ""; - s->info.domain = ""; /* XXX ? */ - - // woo - s->user = user; - - return 0; - } - - int get_params() override { - return 0; - } - - void send_response() override {} - -}; /* RGWSetAttrsRequest */ - -} /* namespace rgw */ - -#endif /* RGW_FILE_H */