1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
7 #include "include/rados/rgw_file.h"
22 #include <boost/intrusive_ptr.hpp>
23 #include <boost/range/adaptor/reversed.hpp>
24 #include <boost/container/flat_map.hpp>
25 #include <boost/variant.hpp>
26 #include <boost/utility/string_ref.hpp>
27 #include <boost/optional.hpp>
29 #include "include/buffer.h"
30 #include "common/cohort_lru.h"
31 #include "common/ceph_timer.h"
32 #include "rgw_common.h"
36 #include "rgw_token.h"
40 * ASSERT_H somehow not defined after all the above (which bring
41 * in common/debug.h [e.g., dout])
43 #include "include/assert.h"
46 #define RGW_RWXMODE (S_IRWXU | S_IRWXG | S_IRWXO)
48 #define RGW_RWMODE (RGW_RWXMODE & \
49 ~(S_IXUSR | S_IXGRP | S_IXOTH))
55 static inline void ignore(T
&&) {}
58 namespace bi
= boost::intrusive
;
62 class RGWWriteRequest
;
64 static inline bool operator <(const struct timespec
& lhs
,
65 const struct timespec
& rhs
) {
66 if (lhs
.tv_sec
== rhs
.tv_sec
)
67 return lhs
.tv_nsec
< rhs
.tv_nsec
;
69 return lhs
.tv_sec
< rhs
.tv_sec
;
72 static inline bool operator ==(const struct timespec
& lhs
,
73 const struct timespec
& rhs
) {
74 return ((lhs
.tv_sec
== rhs
.tv_sec
) &&
75 (lhs
.tv_nsec
== rhs
.tv_nsec
));
80 * The current 64-bit, non-cryptographic hash used here is intended
81 * for prototyping only.
83 * However, the invariant being prototyped is that objects be
84 * identifiable by their hash components alone. We believe this can
85 * be legitimately implemented using 128-hash values for bucket and
86 * object components, together with a cluster-resident cryptographic
87 * key. Since an MD5 or SHA-1 key is 128 bits and the (fast),
88 * non-cryptographic CityHash128 hash algorithm takes a 128-bit seed,
89 * speculatively we could use that for the final hash computations.
95 static constexpr uint64_t seed
= 8675309;
99 fh_key(const rgw_fh_hk
& _hk
)
104 fh_key(const uint64_t bk
, const uint64_t ok
) {
109 fh_key(const uint64_t bk
, const char *_o
) {
111 fh_hk
.object
= XXH64(_o
, ::strlen(_o
), seed
);
114 fh_key(const std::string
& _b
, const std::string
& _o
) {
115 fh_hk
.bucket
= XXH64(_b
.c_str(), _o
.length(), seed
);
116 fh_hk
.object
= XXH64(_o
.c_str(), _o
.length(), seed
);
119 void encode(buffer::list
& bl
) const {
120 ENCODE_START(1, 1, bl
);
121 ::encode(fh_hk
.bucket
, bl
);
122 ::encode(fh_hk
.object
, bl
);
126 void decode(bufferlist::iterator
& bl
) {
128 ::decode(fh_hk
.bucket
, bl
);
129 ::decode(fh_hk
.object
, bl
);
134 WRITE_CLASS_ENCODER(fh_key
);
136 inline bool operator<(const fh_key
& lhs
, const fh_key
& rhs
)
138 return ((lhs
.fh_hk
.bucket
< rhs
.fh_hk
.bucket
) ||
139 ((lhs
.fh_hk
.bucket
== rhs
.fh_hk
.bucket
) &&
140 (lhs
.fh_hk
.object
< rhs
.fh_hk
.object
)));
143 inline bool operator>(const fh_key
& lhs
, const fh_key
& rhs
)
148 inline bool operator==(const fh_key
& lhs
, const fh_key
& rhs
)
150 return ((lhs
.fh_hk
.bucket
== rhs
.fh_hk
.bucket
) &&
151 (lhs
.fh_hk
.object
== rhs
.fh_hk
.object
));
154 inline bool operator!=(const fh_key
& lhs
, const fh_key
& rhs
)
156 return !(lhs
== rhs
);
159 inline bool operator<=(const fh_key
& lhs
, const fh_key
& rhs
)
161 return (lhs
< rhs
) || (lhs
== rhs
);
164 using boost::variant
;
165 using boost::container::flat_map
;
167 class RGWFileHandle
: public cohort::lru::Object
169 struct rgw_file_handle fh
;
173 RGWFileHandle
* bucket
;
174 RGWFileHandle
* parent
;
175 /* const */ std::string name
; /* XXX file or bucket name */
176 /* const */ fh_key fhk
;
178 using lock_guard
= std::lock_guard
<std::mutex
>;
179 using unique_lock
= std::unique_lock
<std::mutex
>;
181 /* TODO: keeping just the last marker is sufficient for
182 * nfs-ganesha 2.4.5; in the near future, nfs-ganesha will
183 * be able to hint the name of the next dirent required,
184 * from which we can directly synthesize a RADOS marker.
185 * using marker_cache_t = flat_map<uint64_t, rgw_obj_key>;
192 uint32_t owner_uid
; /* XXX need Unix attr */
193 uint32_t owner_gid
; /* XXX need Unix attr */
195 struct timespec ctime
;
196 struct timespec mtime
;
197 struct timespec atime
;
198 State() : dev(0), size(0), nlink(1), owner_uid(0), owner_gid(0),
199 ctime
{0,0}, mtime
{0,0}, atime
{0,0} {}
203 RGWWriteRequest
* write_req
;
204 file() : write_req(nullptr) {}
210 static constexpr uint32_t FLAG_NONE
= 0x0000;
213 rgw_obj_key last_marker
;
214 struct timespec last_readdir
;
216 directory() : flags(FLAG_NONE
), last_readdir
{0,0} {}
221 boost::variant
<file
, directory
> variant_type
;
227 const static std::string root_name
;
229 static constexpr uint16_t MAX_DEPTH
= 256;
231 static constexpr uint32_t FLAG_NONE
= 0x0000;
232 static constexpr uint32_t FLAG_OPEN
= 0x0001;
233 static constexpr uint32_t FLAG_ROOT
= 0x0002;
234 static constexpr uint32_t FLAG_CREATE
= 0x0004;
235 static constexpr uint32_t FLAG_CREATING
= 0x0008;
236 static constexpr uint32_t FLAG_DIRECTORY
= 0x0010;
237 static constexpr uint32_t FLAG_BUCKET
= 0x0020;
238 static constexpr uint32_t FLAG_LOCK
= 0x0040;
239 static constexpr uint32_t FLAG_DELETED
= 0x0080;
240 static constexpr uint32_t FLAG_UNLINK_THIS
= 0x0100;
241 static constexpr uint32_t FLAG_LOCKED
= 0x0200;
242 static constexpr uint32_t FLAG_STATELESS_OPEN
= 0x0400;
243 static constexpr uint32_t FLAG_EXACT_MATCH
= 0x0800;
245 #define CREATE_FLAGS(x) \
246 ((x) & ~(RGWFileHandle::FLAG_CREATE|RGWFileHandle::FLAG_LOCK))
248 friend class RGWLibFS
;
251 RGWFileHandle(RGWLibFS
* _fs
, uint32_t fs_inst
)
252 : fs(_fs
), bucket(nullptr), parent(nullptr), variant_type
{directory()},
253 depth(0), flags(FLAG_ROOT
)
256 fh
.fh_type
= RGW_FS_TYPE_DIRECTORY
;
257 variant_type
= directory();
260 state
.unix_mode
= RGW_RWXMODE
|S_IFDIR
;
261 /* pointer to self */
262 fh
.fh_private
= this;
265 void init_rootfs(std::string
& fsid
, const std::string
& object_name
) {
267 fh
.fh_hk
.bucket
= XXH64(fsid
.c_str(), fsid
.length(), fh_key::seed
);
268 fh
.fh_hk
.object
= XXH64(object_name
.c_str(), object_name
.length(),
275 RGWFileHandle(RGWLibFS
* fs
, uint32_t fs_inst
, RGWFileHandle
* _parent
,
276 const fh_key
& _fhk
, std::string
& _name
, uint32_t _flags
)
277 : fs(fs
), bucket(nullptr), parent(_parent
), name(std::move(_name
)),
278 fhk(_fhk
), flags(_flags
) {
280 if (parent
->is_root()) {
281 fh
.fh_type
= RGW_FS_TYPE_DIRECTORY
;
282 variant_type
= directory();
283 flags
|= FLAG_BUCKET
;
285 bucket
= (parent
->flags
& FLAG_BUCKET
) ? parent
287 if (flags
& FLAG_DIRECTORY
) {
288 fh
.fh_type
= RGW_FS_TYPE_DIRECTORY
;
289 variant_type
= directory();
291 fh
.fh_type
= RGW_FS_TYPE_FILE
;
292 variant_type
= file();
296 depth
= parent
->depth
+ 1;
298 /* save constant fhk */
299 fh
.fh_hk
= fhk
.fh_hk
; /* XXX redundant in fh_hk */
304 switch (fh
.fh_type
) {
305 case RGW_FS_TYPE_DIRECTORY
:
306 state
.unix_mode
= RGW_RWXMODE
|S_IFDIR
;
308 case RGW_FS_TYPE_FILE
:
309 state
.unix_mode
= RGW_RWMODE
|S_IFREG
;
314 /* pointer to self */
315 fh
.fh_private
= this;
318 const fh_key
& get_key() const {
322 directory
* get_directory() {
323 return get
<directory
>(&variant_type
);
326 size_t get_size() const { return state
.size
; }
328 const char* stype() {
329 return is_dir() ? "DIR" : "FILE";
332 uint16_t get_depth() const { return depth
; }
334 struct rgw_file_handle
* get_fh() { return &fh
; }
336 RGWLibFS
* get_fs() { return fs
; }
338 RGWFileHandle
* get_parent() { return parent
; }
340 uint32_t get_owner_uid() const { return state
.owner_uid
; }
341 uint32_t get_owner_gid() const { return state
.owner_gid
; }
343 struct timespec
get_ctime() const { return state
.ctime
; }
344 struct timespec
get_mtime() const { return state
.mtime
; }
346 void create_stat(struct stat
* st
, uint32_t mask
) {
347 if (mask
& RGW_SETATTR_UID
)
348 state
.owner_uid
= st
->st_uid
;
350 if (mask
& RGW_SETATTR_GID
)
351 state
.owner_gid
= st
->st_gid
;
353 if (mask
& RGW_SETATTR_MODE
) {
354 switch (fh
.fh_type
) {
355 case RGW_FS_TYPE_DIRECTORY
:
356 state
.unix_mode
= st
->st_mode
|S_IFDIR
;
358 case RGW_FS_TYPE_FILE
:
359 state
.unix_mode
= st
->st_mode
|S_IFREG
;
365 if (mask
& RGW_SETATTR_ATIME
)
366 state
.atime
= st
->st_atim
;
367 if (mask
& RGW_SETATTR_MTIME
)
368 state
.mtime
= st
->st_mtim
;
369 if (mask
& RGW_SETATTR_CTIME
)
370 state
.ctime
= st
->st_ctim
;
373 int stat(struct stat
* st
) {
374 /* partial Unix attrs */
375 memset(st
, 0, sizeof(struct stat
));
376 st
->st_dev
= state
.dev
;
377 st
->st_ino
= fh
.fh_hk
.object
; // XXX
379 st
->st_uid
= state
.owner_uid
;
380 st
->st_gid
= state
.owner_gid
;
382 st
->st_mode
= state
.unix_mode
;
384 #ifdef HAVE_STAT_ST_MTIMESPEC_TV_NSEC
385 st
->st_atimespec
= state
.atime
;
386 st
->st_mtimespec
= state
.mtime
;
387 st
->st_ctimespec
= state
.ctime
;
389 st
->st_atim
= state
.atime
;
390 st
->st_mtim
= state
.mtime
;
391 st
->st_ctim
= state
.ctime
;
394 switch (fh
.fh_type
) {
395 case RGW_FS_TYPE_DIRECTORY
:
396 st
->st_nlink
= state
.nlink
;
398 case RGW_FS_TYPE_FILE
:
400 st
->st_blksize
= 4096;
401 st
->st_size
= state
.size
;
402 st
->st_blocks
= (state
.size
) / 512;
410 const std::string
& bucket_name() const {
413 if (flags
& FLAG_BUCKET
)
415 return bucket
->object_name();
418 const std::string
& object_name() const { return name
; }
420 std::string
full_object_name(bool omit_bucket
= false) const {
422 std::vector
<const std::string
*> segments
;
424 const RGWFileHandle
* tfh
= this;
425 while (tfh
&& !tfh
->is_root() && !(tfh
->is_bucket() && omit_bucket
)) {
426 segments
.push_back(&tfh
->object_name());
427 reserve
+= (1 + tfh
->object_name().length());
431 path
.reserve(reserve
);
432 for (auto& s
: boost::adaptors::reverse(segments
)) {
436 if (!omit_bucket
&& (path
.front() != '/')) // pretty-print
445 inline std::string
relative_object_name() const {
446 return full_object_name(true /* omit_bucket */);
449 inline std::string
format_child_name(const std::string
& cbasename
) const {
450 std::string child_name
{relative_object_name()};
451 if ((child_name
.size() > 0) &&
452 (child_name
.back() != '/'))
454 child_name
+= cbasename
;
458 inline std::string
make_key_name(const char *name
) const {
459 std::string key_name
{full_object_name()};
460 if (key_name
.length() > 0)
466 fh_key
make_fhk(const std::string
& name
) const {
468 return fh_key(fhk
.fh_hk
.object
, name
.c_str());
470 std::string key_name
= make_key_name(name
.c_str());
471 return fh_key(fhk
.fh_hk
.bucket
, key_name
.c_str());
475 void add_marker(uint64_t off
, const rgw_obj_key
& marker
,
478 directory
* d
= get
<directory
>(&variant_type
);
480 unique_lock
guard(mtx
);
481 d
->last_marker
= marker
;
485 const rgw_obj_key
* find_marker(uint64_t off
) const {
488 const directory
* d
= get
<directory
>(&variant_type
);
490 return &d
->last_marker
;
496 bool is_open() const { return flags
& FLAG_OPEN
; }
497 bool is_root() const { return flags
& FLAG_ROOT
; }
498 bool is_bucket() const { return flags
& FLAG_BUCKET
; }
499 bool is_object() const { return !is_bucket(); }
500 bool is_file() const { return (fh
.fh_type
== RGW_FS_TYPE_FILE
); }
501 bool is_dir() const { return (fh
.fh_type
== RGW_FS_TYPE_DIRECTORY
); }
502 bool creating() const { return flags
& FLAG_CREATING
; }
503 bool deleted() const { return flags
& FLAG_DELETED
; }
504 bool stateless_open() const { return flags
& FLAG_STATELESS_OPEN
; }
505 bool has_children() const;
507 int open(uint32_t gsh_flags
) {
508 lock_guard
guard(mtx
);
509 if (! (flags
& FLAG_OPEN
)) {
510 if (gsh_flags
& RGW_OPEN_FLAG_V3
) {
511 flags
|= FLAG_STATELESS_OPEN
;
519 int readdir(rgw_readdir_cb rcb
, void *cb_arg
, uint64_t *offset
, bool *eof
,
521 int write(uint64_t off
, size_t len
, size_t *nbytes
, void *buffer
);
523 int commit(uint64_t offset
, uint64_t length
, uint32_t flags
) {
524 /* NFS3 and NFSv4 COMMIT implementation
525 * the current atomic update strategy doesn't actually permit
526 * clients to read-stable until either CLOSE (NFSv4+) or the
527 * expiration of the active write timer (NFS3). In the
528 * interim, the client may send an arbitrary number of COMMIT
529 * operations which must return a success result */
533 int write_finish(uint32_t flags
= FLAG_NONE
);
536 void open_for_create() {
537 lock_guard
guard(mtx
);
538 flags
|= FLAG_CREATING
;
541 void clear_creating() {
542 lock_guard
guard(mtx
);
543 flags
&= ~FLAG_CREATING
;
546 void inc_nlink(const uint64_t n
) {
550 void set_nlink(const uint64_t n
) {
554 void set_size(const size_t size
) {
558 void set_times(real_time t
) {
559 state
.ctime
= real_clock::to_timespec(t
);
560 state
.mtime
= state
.ctime
;
561 state
.atime
= state
.ctime
;
564 void set_ctime(const struct timespec
&ts
) {
568 void set_mtime(const struct timespec
&ts
) {
572 void set_atime(const struct timespec
&ts
) {
576 void encode(buffer::list
& bl
) const {
577 ENCODE_START(1, 1, bl
);
578 ::encode(uint32_t(fh
.fh_type
), bl
);
579 ::encode(state
.dev
, bl
);
580 ::encode(state
.size
, bl
);
581 ::encode(state
.nlink
, bl
);
582 ::encode(state
.owner_uid
, bl
);
583 ::encode(state
.owner_gid
, bl
);
584 ::encode(state
.unix_mode
, bl
);
585 for (const auto& t
: { state
.ctime
, state
.mtime
, state
.atime
}) {
586 ::encode(real_clock::from_timespec(t
), bl
);
591 void decode(bufferlist::iterator
& bl
) {
594 ::decode(fh_type
, bl
);
595 assert(fh
.fh_type
== fh_type
);
596 ::decode(state
.dev
, bl
);
597 ::decode(state
.size
, bl
);
598 ::decode(state
.nlink
, bl
);
599 ::decode(state
.owner_uid
, bl
);
600 ::decode(state
.owner_gid
, bl
);
601 ::decode(state
.unix_mode
, bl
);
602 ceph::real_time enc_time
;
603 for (auto t
: { &(state
.ctime
), &(state
.mtime
), &(state
.atime
) }) {
604 ::decode(enc_time
, bl
);
605 *t
= real_clock::to_timespec(enc_time
);
610 void encode_attrs(ceph::buffer::list
& ux_key1
,
611 ceph::buffer::list
& ux_attrs1
);
613 void decode_attrs(const ceph::buffer::list
* ux_key1
,
614 const ceph::buffer::list
* ux_attrs1
);
618 bool reclaim() override
;
620 typedef cohort::lru::LRU
<std::mutex
> FhLRU
;
624 // for internal ordering
625 bool operator()(const RGWFileHandle
& lhs
, const RGWFileHandle
& rhs
) const
626 { return (lhs
.get_key() < rhs
.get_key()); }
628 // for external search by fh_key
629 bool operator()(const fh_key
& k
, const RGWFileHandle
& fh
) const
630 { return k
< fh
.get_key(); }
632 bool operator()(const RGWFileHandle
& fh
, const fh_key
& k
) const
633 { return fh
.get_key() < k
; }
638 bool operator()(const RGWFileHandle
& lhs
, const RGWFileHandle
& rhs
) const
639 { return (lhs
.get_key() == rhs
.get_key()); }
641 bool operator()(const fh_key
& k
, const RGWFileHandle
& fh
) const
642 { return k
== fh
.get_key(); }
644 bool operator()(const RGWFileHandle
& fh
, const fh_key
& k
) const
645 { return fh
.get_key() == k
; }
648 typedef bi::link_mode
<bi::safe_link
> link_mode
; /* XXX normal */
649 #if defined(FHCACHE_AVL)
650 typedef bi::avl_set_member_hook
<link_mode
> tree_hook_type
;
653 typedef bi::set_member_hook
<link_mode
> tree_hook_type
;
655 tree_hook_type fh_hook
;
657 typedef bi::member_hook
<
658 RGWFileHandle
, tree_hook_type
, &RGWFileHandle::fh_hook
> FhHook
;
660 #if defined(FHCACHE_AVL)
661 typedef bi::avltree
<RGWFileHandle
, bi::compare
<FhLT
>, FhHook
> FHTree
;
663 typedef bi::rbtree
<RGWFileHandle
, bi::compare
<FhLT
>, FhHook
> FhTree
;
665 typedef cohort::lru::TreeX
<RGWFileHandle
, FhTree
, FhLT
, FhEQ
, fh_key
,
668 ~RGWFileHandle() override
;
670 friend std::ostream
& operator<<(std::ostream
&os
,
671 RGWFileHandle
const &rgw_fh
);
673 class Factory
: public cohort::lru::ObjectFactory
678 RGWFileHandle
* parent
;
685 Factory(RGWLibFS
* fs
, uint32_t fs_inst
, RGWFileHandle
* parent
,
686 const fh_key
& fhk
, std::string
& name
, uint32_t flags
)
687 : fs(fs
), fs_inst(fs_inst
), parent(parent
), fhk(fhk
), name(name
),
690 void recycle (cohort::lru::Object
* o
) override
{
691 /* re-use an existing object */
692 o
->~Object(); // call lru::Object virtual dtor
694 new (o
) RGWFileHandle(fs
, fs_inst
, parent
, fhk
, name
, flags
);
697 cohort::lru::Object
* alloc() override
{
698 return new RGWFileHandle(fs
, fs_inst
, parent
, fhk
, name
, flags
);
702 }; /* RGWFileHandle */
704 WRITE_CLASS_ENCODER(RGWFileHandle
);
706 static inline RGWFileHandle
* get_rgwfh(struct rgw_file_handle
* fh
) {
707 return static_cast<RGWFileHandle
*>(fh
->fh_private
);
710 static inline enum rgw_fh_type
fh_type_of(uint32_t flags
) {
711 enum rgw_fh_type fh_type
;
712 switch(flags
& RGW_LOOKUP_TYPE_FLAGS
)
714 case RGW_LOOKUP_FLAG_DIR
:
715 fh_type
= RGW_FS_TYPE_DIRECTORY
;
717 case RGW_LOOKUP_FLAG_FILE
:
718 fh_type
= RGW_FS_TYPE_FILE
;
721 fh_type
= RGW_FS_TYPE_NIL
;
726 typedef std::tuple
<RGWFileHandle
*, uint32_t> LookupFHResult
;
727 typedef std::tuple
<RGWFileHandle
*, int> MkObjResult
;
733 RGWFileHandle root_fh
;
734 rgw_fh_callback_t invalidate_cb
;
735 void *invalidate_arg
;
738 mutable std::atomic
<uint64_t> refcnt
;
740 RGWFileHandle::FHCache fh_cache
;
741 RGWFileHandle::FhLRU fh_lru
;
743 std::string uid
; // should match user.user_id, iiuc
746 RGWAccessKey key
; // XXXX acc_key
748 static std::atomic
<uint32_t> fs_inst_counter
;
750 static uint32_t write_completion_interval_s
;
753 using lock_guard
= std::lock_guard
<std::mutex
>;
754 using unique_lock
= std::unique_lock
<std::mutex
>;
758 enum class type
: uint8_t { READDIR
} ;
762 event(type t
, const fh_key
& k
, const struct timespec
& ts
)
763 : t(t
), fhk(k
), ts(ts
) {}
766 friend std::ostream
& operator<<(std::ostream
&os
,
767 RGWLibFS::event
const &ev
);
769 using event_vector
= /* boost::small_vector<event, 16> */
772 struct WriteCompletion
774 RGWFileHandle
& rgw_fh
;
776 WriteCompletion(RGWFileHandle
& _fh
) : rgw_fh(_fh
) {
777 rgw_fh
.get_fs()->ref(&rgw_fh
);
781 rgw_fh
.write_finish();
782 rgw_fh
.get_fs()->unref(&rgw_fh
);
786 static ceph::timer
<ceph::mono_clock
> write_timer
;
790 std::atomic
<uint32_t> flags
;
791 std::deque
<event
> events
;
793 State() : flags(0) {}
795 void push_event(const event
& ev
) {
796 events
.push_back(ev
);
800 uint32_t new_inst() {
801 return ++fs_inst_counter
;
804 friend class RGWFileHandle
;
805 friend class RGWLibProcess
;
809 static constexpr uint32_t FLAG_NONE
= 0x0000;
810 static constexpr uint32_t FLAG_CLOSED
= 0x0001;
812 RGWLibFS(CephContext
* _cct
, const char *_uid
, const char *_user_id
,
814 : cct(_cct
), root_fh(this, new_inst()), invalidate_cb(nullptr),
815 invalidate_arg(nullptr), shutdown(false), refcnt(1),
816 fh_cache(cct
->_conf
->rgw_nfs_fhcache_partitions
,
817 cct
->_conf
->rgw_nfs_fhcache_size
),
818 fh_lru(cct
->_conf
->rgw_nfs_lru_lanes
,
819 cct
->_conf
->rgw_nfs_lru_lane_hiwat
),
820 uid(_uid
), key(_user_id
, _key
) {
822 /* no bucket may be named rgw_fs_inst-(.*) */
823 fsid
= RGWFileHandle::root_name
+ "rgw_fs_inst-" +
824 std::to_string(get_inst());
826 root_fh
.init_rootfs(fsid
/* bucket */, RGWFileHandle::root_name
);
828 /* pointer to self */
829 fs
.fs_private
= this;
831 /* expose public root fh */
832 fs
.root_fh
= root_fh
.get_fh();
835 friend void intrusive_ptr_add_ref(const RGWLibFS
* fs
) {
836 fs
->refcnt
.fetch_add(1, std::memory_order_relaxed
);
839 friend void intrusive_ptr_release(const RGWLibFS
* fs
) {
840 if (fs
->refcnt
.fetch_sub(1, std::memory_order_release
) == 0) {
841 std::atomic_thread_fence(std::memory_order_acquire
);
847 intrusive_ptr_add_ref(this);
852 intrusive_ptr_release(this);
855 void stop() { shutdown
= true; }
857 void release_evict(RGWFileHandle
* fh
) {
858 /* remove from cache, releases sentinel ref */
859 fh_cache
.remove(fh
->fh
.fh_hk
.object
, fh
,
860 RGWFileHandle::FHCache::FLAG_LOCK
);
861 /* release call-path ref */
862 (void) fh_lru
.unref(fh
, cohort::lru::FLAG_NONE
);
865 int authorize(RGWRados
* store
) {
866 int ret
= rgw_get_user_info_by_access_key(store
, key
.id
, user
);
868 RGWAccessKey
* key0
= user
.get_key0();
870 (key0
->key
!= key
.key
))
873 return -ERR_USER_SUSPENDED
;
875 /* try external authenticators (ldap for now) */
876 rgw::LDAPHelper
* ldh
= rgwlib
.get_ldh(); /* !nullptr */
878 /* boost filters and/or string_ref may throw on invalid input */
880 token
= rgw::from_base64(key
.id
);
882 token
= std::string("");
884 if (token
.valid() && (ldh
->auth(token
.id
, token
.key
) == 0)) {
885 /* try to store user if it doesn't already exist */
886 if (rgw_get_user_info_by_uid(store
, token
.id
, user
) < 0) {
887 int ret
= rgw_store_user_info(store
, user
, NULL
, NULL
, real_time(),
890 lsubdout(get_context(), rgw
, 10)
891 << "NOTICE: failed to store new user's info: ret=" << ret
900 int register_invalidate(rgw_fh_callback_t cb
, void *arg
, uint32_t flags
) {
902 invalidate_arg
= arg
;
906 /* find RGWFileHandle by id */
907 LookupFHResult
lookup_fh(const fh_key
& fhk
,
908 const uint32_t flags
= RGWFileHandle::FLAG_NONE
) {
911 // cast int32_t(RGWFileHandle::FLAG_NONE) due to strictness of Clang
912 // the cast transfers a lvalue into a rvalue in the ctor
913 // check the commit message for the full details
914 LookupFHResult fhr
{ nullptr, uint32_t(RGWFileHandle::FLAG_NONE
) };
916 RGWFileHandle::FHCache::Latch lat
;
920 fh_cache
.find_latch(fhk
.fh_hk
.object
/* partition selector*/,
921 fhk
/* key */, lat
/* serializer */,
922 RGWFileHandle::FHCache::FLAG_LOCK
);
925 fh
->mtx
.lock(); // XXX !RAII because may-return-LOCKED
926 /* need initial ref from LRU (fast path) */
927 if (! fh_lru
.ref(fh
, cohort::lru::FLAG_INITIAL
)) {
930 goto retry
; /* !LATCHED */
932 /* LATCHED, LOCKED */
933 if (! (flags
& RGWFileHandle::FLAG_LOCK
))
934 fh
->mtx
.unlock(); /* ! LOCKED */
936 lat
.lock
->unlock(); /* !LATCHED */
939 lsubdout(get_context(), rgw
, 17)
940 << __func__
<< " 1 " << *fh
944 } /* lookup_fh(const fh_key&) */
946 /* find or create an RGWFileHandle */
947 LookupFHResult
lookup_fh(RGWFileHandle
* parent
, const char *name
,
948 const uint32_t flags
= RGWFileHandle::FLAG_NONE
) {
951 // cast int32_t(RGWFileHandle::FLAG_NONE) due to strictness of Clang
952 // the cast transfers a lvalue into a rvalue in the ctor
953 // check the commit message for the full details
954 LookupFHResult fhr
{ nullptr, uint32_t(RGWFileHandle::FLAG_NONE
) };
956 /* mount is stale? */
957 if (state
.flags
& FLAG_CLOSED
)
960 RGWFileHandle::FHCache::Latch lat
;
962 std::string obj_name
{name
};
963 std::string key_name
{parent
->make_key_name(name
)};
965 lsubdout(get_context(), rgw
, 10)
966 << __func__
<< " lookup called on "
967 << parent
->object_name() << " for " << key_name
968 << " (" << obj_name
<< ")"
971 fh_key fhk
= parent
->make_fhk(key_name
);
975 fh_cache
.find_latch(fhk
.fh_hk
.object
/* partition selector*/,
976 fhk
/* key */, lat
/* serializer */,
977 RGWFileHandle::FHCache::FLAG_LOCK
);
980 fh
->mtx
.lock(); // XXX !RAII because may-return-LOCKED
981 if (fh
->flags
& RGWFileHandle::FLAG_DELETED
) {
982 /* for now, delay briefly and retry */
985 std::this_thread::sleep_for(std::chrono::milliseconds(20));
986 goto retry
; /* !LATCHED */
988 /* need initial ref from LRU (fast path) */
989 if (! fh_lru
.ref(fh
, cohort::lru::FLAG_INITIAL
)) {
992 goto retry
; /* !LATCHED */
994 /* LATCHED, LOCKED */
995 if (! (flags
& RGWFileHandle::FLAG_LOCK
))
996 fh
->mtx
.unlock(); /* ! LOCKED */
998 /* make or re-use handle */
999 RGWFileHandle::Factory
prototype(this, get_inst(), parent
, fhk
,
1000 obj_name
, CREATE_FLAGS(flags
));
1001 fh
= static_cast<RGWFileHandle
*>(
1002 fh_lru
.insert(&prototype
,
1003 cohort::lru::Edge::MRU
,
1004 cohort::lru::FLAG_INITIAL
));
1006 /* lock fh (LATCHED) */
1007 if (flags
& RGWFileHandle::FLAG_LOCK
)
1009 /* inserts, releasing latch */
1010 fh_cache
.insert_latched(fh
, lat
, RGWFileHandle::FHCache::FLAG_UNLOCK
);
1011 get
<1>(fhr
) |= RGWFileHandle::FLAG_CREATE
;
1012 /* ref parent (non-initial ref cannot fail on valid object) */
1013 if (! parent
->is_root()) {
1014 (void) fh_lru
.ref(parent
, cohort::lru::FLAG_NONE
);
1016 goto out
; /* !LATCHED */
1019 goto retry
; /* !LATCHED */
1022 lat
.lock
->unlock(); /* !LATCHED */
1026 lsubdout(get_context(), rgw
, 17)
1027 << __func__
<< " 2 " << *fh
1031 } /* lookup_fh(RGWFileHandle*, const char *, const uint32_t) */
1033 inline void unref(RGWFileHandle
* fh
) {
1034 if (likely(! fh
->is_root())) {
1035 (void) fh_lru
.unref(fh
, cohort::lru::FLAG_NONE
);
1039 inline RGWFileHandle
* ref(RGWFileHandle
* fh
) {
1040 if (likely(! fh
->is_root())) {
1041 fh_lru
.ref(fh
, cohort::lru::FLAG_NONE
);
1046 int getattr(RGWFileHandle
* rgw_fh
, struct stat
* st
);
1048 int setattr(RGWFileHandle
* rgw_fh
, struct stat
* st
, uint32_t mask
,
1051 LookupFHResult
stat_bucket(RGWFileHandle
* parent
,
1052 const char *path
, uint32_t flags
);
1054 LookupFHResult
stat_leaf(RGWFileHandle
* parent
, const char *path
,
1055 enum rgw_fh_type type
= RGW_FS_TYPE_NIL
,
1056 uint32_t flags
= RGWFileHandle::FLAG_NONE
);
1058 int read(RGWFileHandle
* rgw_fh
, uint64_t offset
, size_t length
,
1059 size_t* bytes_read
, void* buffer
, uint32_t flags
);
1061 int rename(RGWFileHandle
* old_fh
, RGWFileHandle
* new_fh
,
1062 const char *old_name
, const char *new_name
);
1064 MkObjResult
create(RGWFileHandle
* parent
, const char *name
, struct stat
*st
,
1065 uint32_t mask
, uint32_t flags
);
1067 MkObjResult
mkdir(RGWFileHandle
* parent
, const char *name
, struct stat
*st
,
1068 uint32_t mask
, uint32_t flags
);
1069 MkObjResult
mkdir2(RGWFileHandle
* parent
, const char *name
, struct stat
*st
,
1070 uint32_t mask
, uint32_t flags
);
1072 int unlink(RGWFileHandle
* rgw_fh
, const char *name
,
1073 uint32_t flags
= FLAG_NONE
);
1075 /* find existing RGWFileHandle */
1076 RGWFileHandle
* lookup_handle(struct rgw_fh_hk fh_hk
) {
1078 if (state
.flags
& FLAG_CLOSED
)
1081 RGWFileHandle::FHCache::Latch lat
;
1086 fh_cache
.find_latch(fhk
.fh_hk
.object
/* partition selector*/,
1087 fhk
/* key */, lat
/* serializer */,
1088 RGWFileHandle::FHCache::FLAG_LOCK
);
1091 lsubdout(get_context(), rgw
, 0)
1092 << __func__
<< " handle lookup failed <"
1093 << fhk
.fh_hk
.bucket
<< "," << fhk
.fh_hk
.object
<< ">"
1094 << "(need persistent handles)"
1099 if (fh
->flags
& RGWFileHandle::FLAG_DELETED
) {
1100 /* for now, delay briefly and retry */
1102 fh
->mtx
.unlock(); /* !LOCKED */
1103 std::this_thread::sleep_for(std::chrono::milliseconds(20));
1104 goto retry
; /* !LATCHED */
1106 if (! fh_lru
.ref(fh
, cohort::lru::FLAG_INITIAL
)) {
1109 goto retry
; /* !LATCHED */
1112 fh
->mtx
.unlock(); /* !LOCKED */
1114 lat
.lock
->unlock(); /* !LATCHED */
1116 /* special case: lookup root_fh */
1118 if (unlikely(fh_hk
== root_fh
.fh
.fh_hk
)) {
1127 CephContext
* get_context() {
1131 struct rgw_fs
* get_fs() { return &fs
; }
1133 uint32_t get_inst() { return root_fh
.state
.dev
; }
1135 RGWUserInfo
* get_user() { return &user
; }
1141 static inline std::string
make_uri(const std::string
& bucket_name
,
1142 const std::string
& object_name
) {
1143 std::string
uri("/");
1144 uri
.reserve(bucket_name
.length() + object_name
.length() + 2);
1152 read directory content (buckets)
1155 class RGWListBucketsRequest
: public RGWLibRequest
,
1156 public RGWListBuckets
/* RGWOp */
1159 RGWFileHandle
* rgw_fh
;
1166 RGWListBucketsRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
1167 RGWFileHandle
* _rgw_fh
, rgw_readdir_cb _rcb
,
1168 void* _cb_arg
, uint64_t* _offset
)
1169 : RGWLibRequest(_cct
, _user
), rgw_fh(_rgw_fh
), offset(_offset
),
1170 cb_arg(_cb_arg
), rcb(_rcb
), ix(0), d_count(0) {
1171 const auto& mk
= rgw_fh
->find_marker(*offset
);
1178 bool only_bucket() override
{ return false; }
1180 int op_init() override
{
1181 // assign store, s, and dialect_handler
1182 RGWObjectCtx
* rados_ctx
1183 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
1184 // framework promises to call op_init after parent init
1186 RGWOp::init(rados_ctx
->store
, get_state(), this);
1187 op
= this; // assign self as op: REQUIRED
1191 int header_init() override
{
1192 struct req_state
* s
= get_state();
1193 s
->info
.method
= "GET";
1196 /* XXX derp derp derp */
1197 s
->relative_uri
= "/";
1198 s
->info
.request_uri
= "/"; // XXX
1199 s
->info
.effective_uri
= "/";
1200 s
->info
.request_params
= "";
1201 s
->info
.domain
= ""; /* XXX ? */
1209 int get_params() override
{
1210 limit
= -1; /* no limit */
1214 void send_response_begin(bool has_buckets
) override
{
1218 void send_response_data(RGWUserBuckets
& buckets
) override
{
1221 map
<string
, RGWBucketEnt
>& m
= buckets
.get_buckets();
1222 for (const auto& iter
: m
) {
1223 boost::string_ref marker
{iter
.first
};
1224 const RGWBucketEnt
& ent
= iter
.second
;
1225 if (! this->operator()(ent
.bucket
.name
, marker
)) {
1226 /* caller cannot accept more */
1227 lsubdout(cct
, rgw
, 5) << "ListBuckets rcb failed"
1228 << " dirent=" << ent
.bucket
.name
1229 << " call count=" << ix
1235 } /* send_response_data */
1237 void send_response_end() override
{
1241 int operator()(const boost::string_ref
& name
,
1242 const boost::string_ref
& marker
) {
1243 uint64_t off
= XXH64(name
.data(), name
.length(), fh_key::seed
);
1245 /* update traversal cache */
1246 rgw_fh
->add_marker(off
, rgw_obj_key
{marker
.data(), ""},
1247 RGW_FS_TYPE_DIRECTORY
);
1249 return rcb(name
.data(), cb_arg
, off
, RGW_LOOKUP_FLAG_DIR
);
1253 lsubdout(cct
, rgw
, 15) << "READDIR offset: " << *offset
1254 << " is_truncated: " << is_truncated
1256 return !is_truncated
;
1259 }; /* RGWListBucketsRequest */
1262 read directory content (bucket objects)
1265 class RGWReaddirRequest
: public RGWLibRequest
,
1266 public RGWListBucket
/* RGWOp */
1269 RGWFileHandle
* rgw_fh
;
1276 RGWReaddirRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
1277 RGWFileHandle
* _rgw_fh
, rgw_readdir_cb _rcb
,
1278 void* _cb_arg
, uint64_t* _offset
)
1279 : RGWLibRequest(_cct
, _user
), rgw_fh(_rgw_fh
), offset(_offset
),
1280 cb_arg(_cb_arg
), rcb(_rcb
), ix(0), d_count(0) {
1281 const auto& mk
= rgw_fh
->find_marker(*offset
);
1285 default_max
= 1000; // XXX was being omitted
1289 bool only_bucket() override
{ return false; }
1291 int op_init() override
{
1292 // assign store, s, and dialect_handler
1293 RGWObjectCtx
* rados_ctx
1294 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
1295 // framework promises to call op_init after parent init
1297 RGWOp::init(rados_ctx
->store
, get_state(), this);
1298 op
= this; // assign self as op: REQUIRED
1302 int header_init() override
{
1303 struct req_state
* s
= get_state();
1304 s
->info
.method
= "GET";
1307 /* XXX derp derp derp */
1308 std::string uri
= "/" + rgw_fh
->bucket_name() + "/";
1309 s
->relative_uri
= uri
;
1310 s
->info
.request_uri
= uri
; // XXX
1311 s
->info
.effective_uri
= uri
;
1312 s
->info
.request_params
= "";
1313 s
->info
.domain
= ""; /* XXX ? */
1318 prefix
= rgw_fh
->relative_object_name();
1319 if (prefix
.length() > 0)
1326 int operator()(const boost::string_ref name
, const rgw_obj_key
& marker
,
1329 assert(name
.length() > 0); // XXX
1331 /* hash offset of name in parent (short name) for NFS readdir cookie */
1332 uint64_t off
= XXH64(name
.data(), name
.length(), fh_key::seed
);
1334 /* update traversal cache */
1335 rgw_fh
->add_marker(off
, marker
, type
);
1337 return rcb(name
.data(), cb_arg
, off
,
1338 (type
== RGW_FS_TYPE_DIRECTORY
) ?
1339 RGW_LOOKUP_FLAG_DIR
:
1340 RGW_LOOKUP_FLAG_FILE
);
1343 int get_params() override
{
1348 void send_response() override
{
1349 struct req_state
* s
= get_state();
1350 for (const auto& iter
: objs
) {
1352 boost::string_ref sref
{iter
.key
.name
};
1354 lsubdout(cct
, rgw
, 15) << "readdir objects prefix: " << prefix
1355 << " obj: " << sref
<< dendl
;
1357 size_t last_del
= sref
.find_last_of('/');
1358 if (last_del
!= string::npos
)
1359 sref
.remove_prefix(last_del
+1);
1361 /* leaf directory? */
1365 lsubdout(cct
, rgw
, 15) << "RGWReaddirRequest "
1367 << "list uri=" << s
->relative_uri
<< " "
1368 << " prefix=" << prefix
<< " "
1369 << " obj path=" << iter
.key
.name
1370 << " (" << sref
<< ")" << ""
1373 if(! this->operator()(sref
, next_marker
, RGW_FS_TYPE_FILE
)) {
1374 /* caller cannot accept more */
1375 lsubdout(cct
, rgw
, 5) << "readdir rcb failed"
1376 << " dirent=" << sref
.data()
1377 << " call count=" << ix
1383 for (auto& iter
: common_prefixes
) {
1385 lsubdout(cct
, rgw
, 15) << "readdir common prefixes prefix: " << prefix
1386 << " iter first: " << iter
.first
1387 << " iter second: " << iter
.second
1390 /* XXX aieee--I have seen this case! */
1391 if (iter
.first
== "/")
1394 /* it's safest to modify the element in place--a suffix-modifying
1395 * string_ref operation is problematic since ULP rgw_file callers
1396 * will ultimately need a c-string */
1397 if (iter
.first
.back() == '/')
1398 const_cast<std::string
&>(iter
.first
).pop_back();
1400 boost::string_ref sref
{iter
.first
};
1402 size_t last_del
= sref
.find_last_of('/');
1403 if (last_del
!= string::npos
)
1404 sref
.remove_prefix(last_del
+1);
1406 lsubdout(cct
, rgw
, 15) << "RGWReaddirRequest "
1408 << "list uri=" << s
->relative_uri
<< " "
1409 << " prefix=" << prefix
<< " "
1410 << " cpref=" << sref
1413 this->operator()(sref
, next_marker
, RGW_FS_TYPE_DIRECTORY
);
1418 virtual void send_versioned_response() {
1423 lsubdout(cct
, rgw
, 15) << "READDIR offset: " << *offset
1424 << " next marker: " << next_marker
1425 << " is_truncated: " << is_truncated
1427 return !is_truncated
;
1430 }; /* RGWReaddirRequest */
1433 dir has-children predicate (bucket objects)
1436 class RGWRMdirCheck
: public RGWLibRequest
,
1437 public RGWListBucket
/* RGWOp */
1440 const RGWFileHandle
* rgw_fh
;
1444 RGWRMdirCheck (CephContext
* _cct
, RGWUserInfo
*_user
,
1445 const RGWFileHandle
* _rgw_fh
)
1446 : RGWLibRequest(_cct
, _user
), rgw_fh(_rgw_fh
), valid(false),
1447 has_children(false) {
1452 bool only_bucket() override
{ return false; }
1454 int op_init() override
{
1455 // assign store, s, and dialect_handler
1456 RGWObjectCtx
* rados_ctx
1457 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
1458 // framework promises to call op_init after parent init
1460 RGWOp::init(rados_ctx
->store
, get_state(), this);
1461 op
= this; // assign self as op: REQUIRED
1465 int header_init() override
{
1466 struct req_state
* s
= get_state();
1467 s
->info
.method
= "GET";
1470 std::string uri
= "/" + rgw_fh
->bucket_name() + "/";
1471 s
->relative_uri
= uri
;
1472 s
->info
.request_uri
= uri
;
1473 s
->info
.effective_uri
= uri
;
1474 s
->info
.request_params
= "";
1475 s
->info
.domain
= ""; /* XXX ? */
1479 prefix
= rgw_fh
->relative_object_name();
1480 if (prefix
.length() > 0)
1487 int get_params() override
{
1492 void send_response() override
{
1494 if ((objs
.size() > 1) ||
1496 (objs
.front().key
.name
!= prefix
))) {
1497 has_children
= true;
1500 for (auto& iter
: common_prefixes
) {
1501 /* readdir never produces a name for this case */
1502 if (iter
.first
== "/")
1504 has_children
= true;
1509 virtual void send_versioned_response() {
1513 }; /* RGWRMdirCheck */
1519 class RGWCreateBucketRequest
: public RGWLibRequest
,
1520 public RGWCreateBucket
/* RGWOp */
1525 RGWCreateBucketRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
1527 : RGWLibRequest(_cct
, _user
), uri(_uri
) {
1531 bool only_bucket() override
{ return false; }
1533 int read_permissions(RGWOp
* op_obj
) override
{
1534 /* we ARE a 'create bucket' request (cf. rgw_rest.cc, ll. 1305-6) */
1538 int op_init() override
{
1539 // assign store, s, and dialect_handler
1540 RGWObjectCtx
* rados_ctx
1541 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
1542 // framework promises to call op_init after parent init
1544 RGWOp::init(rados_ctx
->store
, get_state(), this);
1545 op
= this; // assign self as op: REQUIRED
1549 int header_init() override
{
1551 struct req_state
* s
= get_state();
1552 s
->info
.method
= "PUT";
1555 /* XXX derp derp derp */
1556 s
->relative_uri
= uri
;
1557 s
->info
.request_uri
= uri
; // XXX
1558 s
->info
.effective_uri
= uri
;
1559 s
->info
.request_params
= "";
1560 s
->info
.domain
= ""; /* XXX ? */
1568 int get_params() override
{
1569 struct req_state
* s
= get_state();
1570 RGWAccessControlPolicy_S3
s3policy(s
->cct
);
1571 /* we don't have (any) headers, so just create canned ACLs */
1572 int ret
= s3policy
.create_canned(s
->owner
, s
->bucket_owner
, s
->canned_acl
);
1577 void send_response() override
{
1578 /* TODO: something (maybe) */
1580 }; /* RGWCreateBucketRequest */
1586 class RGWDeleteBucketRequest
: public RGWLibRequest
,
1587 public RGWDeleteBucket
/* RGWOp */
1592 RGWDeleteBucketRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
1594 : RGWLibRequest(_cct
, _user
), uri(_uri
) {
1598 bool only_bucket() override
{ return true; }
1600 int op_init() override
{
1601 // assign store, s, and dialect_handler
1602 RGWObjectCtx
* rados_ctx
1603 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
1604 // framework promises to call op_init after parent init
1606 RGWOp::init(rados_ctx
->store
, get_state(), this);
1607 op
= this; // assign self as op: REQUIRED
1611 int header_init() override
{
1613 struct req_state
* s
= get_state();
1614 s
->info
.method
= "DELETE";
1617 /* XXX derp derp derp */
1618 s
->relative_uri
= uri
;
1619 s
->info
.request_uri
= uri
; // XXX
1620 s
->info
.effective_uri
= uri
;
1621 s
->info
.request_params
= "";
1622 s
->info
.domain
= ""; /* XXX ? */
1630 void send_response() override
{}
1632 }; /* RGWDeleteBucketRequest */
1637 class RGWPutObjRequest
: public RGWLibRequest
,
1638 public RGWPutObj
/* RGWOp */
1641 const std::string
& bucket_name
;
1642 const std::string
& obj_name
;
1643 buffer::list
& bl
; /* XXX */
1644 size_t bytes_written
;
1646 RGWPutObjRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
1647 const std::string
& _bname
, const std::string
& _oname
,
1649 : RGWLibRequest(_cct
, _user
), bucket_name(_bname
), obj_name(_oname
),
1650 bl(_bl
), bytes_written(0) {
1654 bool only_bucket() override
{ return true; }
1656 int op_init() override
{
1657 // assign store, s, and dialect_handler
1658 RGWObjectCtx
* rados_ctx
1659 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
1660 // framework promises to call op_init after parent init
1662 RGWOp::init(rados_ctx
->store
, get_state(), this);
1663 op
= this; // assign self as op: REQUIRED
1665 int rc
= valid_s3_object_name(obj_name
);
1672 int header_init() override
{
1674 struct req_state
* s
= get_state();
1675 s
->info
.method
= "PUT";
1678 /* XXX derp derp derp */
1679 std::string uri
= make_uri(bucket_name
, obj_name
);
1680 s
->relative_uri
= uri
;
1681 s
->info
.request_uri
= uri
; // XXX
1682 s
->info
.effective_uri
= uri
;
1683 s
->info
.request_params
= "";
1684 s
->info
.domain
= ""; /* XXX ? */
1686 /* XXX required in RGWOp::execute() */
1687 s
->content_length
= bl
.length();
1695 int get_params() override
{
1696 struct req_state
* s
= get_state();
1697 RGWAccessControlPolicy_S3
s3policy(s
->cct
);
1698 /* we don't have (any) headers, so just create canned ACLs */
1699 int ret
= s3policy
.create_canned(s
->owner
, s
->bucket_owner
, s
->canned_acl
);
1704 int get_data(buffer::list
& _bl
) override
{
1705 /* XXX for now, use sharing semantics */
1707 uint32_t len
= _bl
.length();
1708 bytes_written
+= len
;
1712 void send_response() override
{}
1714 int verify_params() override
{
1715 if (bl
.length() > cct
->_conf
->rgw_max_put_size
)
1716 return -ERR_TOO_LARGE
;
1720 }; /* RGWPutObjRequest */
1726 class RGWReadRequest
: public RGWLibRequest
,
1727 public RGWGetObj
/* RGWOp */
1730 RGWFileHandle
* rgw_fh
;
1733 size_t read_resid
; /* initialize to len, <= sizeof(ulp_buffer) */
1734 bool do_hexdump
= false;
1736 RGWReadRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
1737 RGWFileHandle
* _rgw_fh
, uint64_t off
, uint64_t len
,
1739 : RGWLibRequest(_cct
, _user
), rgw_fh(_rgw_fh
), ulp_buffer(_ulp_buffer
),
1740 nread(0), read_resid(len
) {
1743 /* fixup RGWGetObj (already know range parameters) */
1744 RGWGetObj::range_parsed
= true;
1745 RGWGetObj::get_data
= true; // XXX
1746 RGWGetObj::partial_content
= true;
1747 RGWGetObj::ofs
= off
;
1748 RGWGetObj::end
= off
+ len
;
1751 bool only_bucket() override
{ return false; }
1753 int op_init() override
{
1754 // assign store, s, and dialect_handler
1755 RGWObjectCtx
* rados_ctx
1756 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
1757 // framework promises to call op_init after parent init
1759 RGWOp::init(rados_ctx
->store
, get_state(), this);
1760 op
= this; // assign self as op: REQUIRED
1764 int header_init() override
{
1766 struct req_state
* s
= get_state();
1767 s
->info
.method
= "GET";
1770 /* XXX derp derp derp */
1771 s
->relative_uri
= make_uri(rgw_fh
->bucket_name(),
1772 rgw_fh
->relative_object_name());
1773 s
->info
.request_uri
= s
->relative_uri
; // XXX
1774 s
->info
.effective_uri
= s
->relative_uri
;
1775 s
->info
.request_params
= "";
1776 s
->info
.domain
= ""; /* XXX ? */
1784 int get_params() override
{
1788 int send_response_data(ceph::buffer::list
& bl
, off_t bl_off
,
1789 off_t bl_len
) override
{
1791 for (auto& bp
: bl
.buffers()) {
1792 /* if for some reason bl_off indicates the start-of-data is not at
1793 * the current buffer::ptr, skip it and account */
1794 if (bl_off
> bp
.length()) {
1795 bl_off
-= bp
.length();
1798 /* read no more than read_resid */
1799 bytes
= std::min(read_resid
, size_t(bp
.length()-bl_off
));
1800 memcpy(static_cast<char*>(ulp_buffer
)+nread
, bp
.c_str()+bl_off
, bytes
);
1801 read_resid
-= bytes
; /* reduce read_resid by bytes read */
1804 /* stop if we have no residual ulp_buffer */
1811 int send_response_data_error() override
{
1812 /* S3 implementation just sends nothing--there is no side effect
1813 * to simulate here */
1817 }; /* RGWReadRequest */
1823 class RGWDeleteObjRequest
: public RGWLibRequest
,
1824 public RGWDeleteObj
/* RGWOp */
1827 const std::string
& bucket_name
;
1828 const std::string
& obj_name
;
1830 RGWDeleteObjRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
1831 const std::string
& _bname
, const std::string
& _oname
)
1832 : RGWLibRequest(_cct
, _user
), bucket_name(_bname
), obj_name(_oname
) {
1836 bool only_bucket() override
{ return true; }
1838 int op_init() override
{
1839 // assign store, s, and dialect_handler
1840 RGWObjectCtx
* rados_ctx
1841 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
1842 // framework promises to call op_init after parent init
1844 RGWOp::init(rados_ctx
->store
, get_state(), this);
1845 op
= this; // assign self as op: REQUIRED
1849 int header_init() override
{
1851 struct req_state
* s
= get_state();
1852 s
->info
.method
= "DELETE";
1855 /* XXX derp derp derp */
1856 std::string uri
= make_uri(bucket_name
, obj_name
);
1857 s
->relative_uri
= uri
;
1858 s
->info
.request_uri
= uri
; // XXX
1859 s
->info
.effective_uri
= uri
;
1860 s
->info
.request_params
= "";
1861 s
->info
.domain
= ""; /* XXX ? */
1869 void send_response() override
{}
1871 }; /* RGWDeleteObjRequest */
1873 class RGWStatObjRequest
: public RGWLibRequest
,
1874 public RGWGetObj
/* RGWOp */
1877 const std::string
& bucket_name
;
1878 const std::string
& obj_name
;
1882 static constexpr uint32_t FLAG_NONE
= 0x000;
1884 RGWStatObjRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
1885 const std::string
& _bname
, const std::string
& _oname
,
1887 : RGWLibRequest(_cct
, _user
), bucket_name(_bname
), obj_name(_oname
),
1888 _size(0), flags(_flags
) {
1891 /* fixup RGWGetObj (already know range parameters) */
1892 RGWGetObj::range_parsed
= true;
1893 RGWGetObj::get_data
= false; // XXX
1894 RGWGetObj::partial_content
= true;
1896 RGWGetObj::end
= UINT64_MAX
;
1899 const string
name() override
{ return "stat_obj"; }
1900 RGWOpType
get_type() override
{ return RGW_OP_STAT_OBJ
; }
1902 real_time
get_mtime() const {
1907 uint64_t get_size() { return _size
; }
1908 real_time
ctime() { return mod_time
; } // XXX
1909 real_time
mtime() { return mod_time
; }
1910 std::map
<string
, bufferlist
>& get_attrs() { return attrs
; }
1912 buffer::list
* get_attr(const std::string
& k
) {
1913 auto iter
= attrs
.find(k
);
1914 return (iter
!= attrs
.end()) ? &(iter
->second
) : nullptr;
1917 bool only_bucket() override
{ return false; }
1919 int op_init() override
{
1920 // assign store, s, and dialect_handler
1921 RGWObjectCtx
* rados_ctx
1922 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
1923 // framework promises to call op_init after parent init
1925 RGWOp::init(rados_ctx
->store
, get_state(), this);
1926 op
= this; // assign self as op: REQUIRED
1930 int header_init() override
{
1932 struct req_state
* s
= get_state();
1933 s
->info
.method
= "GET";
1936 /* XXX derp derp derp */
1937 s
->relative_uri
= make_uri(bucket_name
, obj_name
);
1938 s
->info
.request_uri
= s
->relative_uri
; // XXX
1939 s
->info
.effective_uri
= s
->relative_uri
;
1940 s
->info
.request_params
= "";
1941 s
->info
.domain
= ""; /* XXX ? */
1949 int get_params() override
{
1953 int send_response_data(ceph::buffer::list
& _bl
, off_t s_off
,
1954 off_t e_off
) override
{
1956 /* XXX save attrs? */
1960 int send_response_data_error() override
{
1965 void execute() override
{
1966 RGWGetObj::execute();
1967 _size
= get_state()->obj_size
;
1970 }; /* RGWStatObjRequest */
1972 class RGWStatBucketRequest
: public RGWLibRequest
,
1973 public RGWStatBucket
/* RGWOp */
1977 std::map
<std::string
, buffer::list
> attrs
;
1979 RGWStatBucketRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
1980 const std::string
& _path
)
1981 : RGWLibRequest(_cct
, _user
) {
1986 buffer::list
* get_attr(const std::string
& k
) {
1987 auto iter
= attrs
.find(k
);
1988 return (iter
!= attrs
.end()) ? &(iter
->second
) : nullptr;
1991 real_time
get_ctime() const {
1992 return bucket
.creation_time
;
1995 bool only_bucket() override
{ return false; }
1997 int op_init() override
{
1998 // assign store, s, and dialect_handler
1999 RGWObjectCtx
* rados_ctx
2000 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
2001 // framework promises to call op_init after parent init
2003 RGWOp::init(rados_ctx
->store
, get_state(), this);
2004 op
= this; // assign self as op: REQUIRED
2008 int header_init() override
{
2010 struct req_state
* s
= get_state();
2011 s
->info
.method
= "GET";
2014 /* XXX derp derp derp */
2015 s
->relative_uri
= uri
;
2016 s
->info
.request_uri
= uri
; // XXX
2017 s
->info
.effective_uri
= uri
;
2018 s
->info
.request_params
= "";
2019 s
->info
.domain
= ""; /* XXX ? */
2027 virtual int get_params() {
2031 void send_response() override
{
2032 bucket
.creation_time
= get_state()->bucket_info
.creation_time
;
2033 std::swap(attrs
, get_state()->bucket_attrs
);
2037 return (bucket
.bucket
.name
.length() > 0);
2040 }; /* RGWStatBucketRequest */
2042 class RGWStatLeafRequest
: public RGWLibRequest
,
2043 public RGWListBucket
/* RGWOp */
2046 RGWFileHandle
* rgw_fh
;
2052 RGWStatLeafRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
2053 RGWFileHandle
* _rgw_fh
, const std::string
& _path
)
2054 : RGWLibRequest(_cct
, _user
), rgw_fh(_rgw_fh
), path(_path
),
2055 matched(false), is_dir(false), exact_matched(false) {
2056 default_max
= 1000; // logical max {"foo", "foo/"}
2060 bool only_bucket() override
{ return false; }
2062 int op_init() override
{
2063 // assign store, s, and dialect_handler
2064 RGWObjectCtx
* rados_ctx
2065 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
2066 // framework promises to call op_init after parent init
2068 RGWOp::init(rados_ctx
->store
, get_state(), this);
2069 op
= this; // assign self as op: REQUIRED
2073 int header_init() override
{
2075 struct req_state
* s
= get_state();
2076 s
->info
.method
= "GET";
2079 /* XXX derp derp derp */
2080 std::string uri
= "/" + rgw_fh
->bucket_name() + "/";
2081 s
->relative_uri
= uri
;
2082 s
->info
.request_uri
= uri
; // XXX
2083 s
->info
.effective_uri
= uri
;
2084 s
->info
.request_params
= "";
2085 s
->info
.domain
= ""; /* XXX ? */
2090 prefix
= rgw_fh
->relative_object_name();
2091 if (prefix
.length() > 0)
2099 int get_params() override
{
2104 void send_response() override
{
2105 struct req_state
* s
= get_state();
2107 for (const auto& iter
: objs
) {
2108 auto& name
= iter
.key
.name
;
2109 lsubdout(cct
, rgw
, 15) << "RGWStatLeafRequest "
2111 << "list uri=" << s
->relative_uri
<< " "
2112 << " prefix=" << prefix
<< " "
2113 << " obj path=" << name
<< ""
2114 << " target = " << path
<< ""
2116 /* XXX is there a missing match-dir case (trailing '/')? */
2119 exact_matched
= true;
2123 for (auto& iter
: common_prefixes
) {
2124 auto& name
= iter
.first
;
2125 lsubdout(cct
, rgw
, 15) << "RGWStatLeafRequest "
2127 << "list uri=" << s
->relative_uri
<< " "
2128 << " prefix=" << prefix
<< " "
2129 << " pref path=" << name
<< " (not chomped)"
2130 << " target = " << path
<< ""
2138 virtual void send_versioned_response() {
2141 }; /* RGWStatLeafRequest */
2147 class RGWWriteRequest
: public RGWLibContinuedReq
,
2148 public RGWPutObj
/* RGWOp */
2151 const std::string
& bucket_name
;
2152 const std::string
& obj_name
;
2153 RGWFileHandle
* rgw_fh
;
2154 RGWPutObjProcessor
*processor
;
2159 size_t bytes_written
;
2163 RGWWriteRequest(CephContext
* _cct
, RGWUserInfo
*_user
, RGWFileHandle
* _fh
,
2164 const std::string
& _bname
, const std::string
& _oname
)
2165 : RGWLibContinuedReq(_cct
, _user
), bucket_name(_bname
), obj_name(_oname
),
2166 rgw_fh(_fh
), processor(nullptr), real_ofs(0), bytes_written(0),
2167 multipart(false), eio(false) {
2169 int ret
= header_init();
2171 ret
= init_from_header(get_state());
2176 bool only_bucket() override
{ return true; }
2178 int op_init() override
{
2179 // assign store, s, and dialect_handler
2180 RGWObjectCtx
* rados_ctx
2181 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
2182 // framework promises to call op_init after parent init
2184 RGWOp::init(rados_ctx
->store
, get_state(), this);
2185 op
= this; // assign self as op: REQUIRED
2189 int header_init() override
{
2191 struct req_state
* s
= get_state();
2192 s
->info
.method
= "PUT";
2195 /* XXX derp derp derp */
2196 std::string uri
= make_uri(bucket_name
, obj_name
);
2197 s
->relative_uri
= uri
;
2198 s
->info
.request_uri
= uri
; // XXX
2199 s
->info
.effective_uri
= uri
;
2200 s
->info
.request_params
= "";
2201 s
->info
.domain
= ""; /* XXX ? */
2209 RGWPutObjProcessor
*select_processor(RGWObjectCtx
& obj_ctx
,
2210 bool *is_multipart
) override
{
2211 struct req_state
* s
= get_state();
2212 uint64_t part_size
= s
->cct
->_conf
->rgw_obj_stripe_size
;
2213 RGWPutObjProcessor_Atomic
*processor
=
2214 new RGWPutObjProcessor_Atomic(obj_ctx
, s
->bucket_info
, s
->bucket
,
2215 s
->object
.name
, part_size
, s
->req_id
,
2216 s
->bucket_info
.versioning_enabled());
2217 processor
->set_olh_epoch(olh_epoch
);
2218 processor
->set_version_id(version_id
);
2222 int get_params() override
{
2223 struct req_state
* s
= get_state();
2224 RGWAccessControlPolicy_S3
s3policy(s
->cct
);
2225 /* we don't have (any) headers, so just create canned ACLs */
2226 int ret
= s3policy
.create_canned(s
->owner
, s
->bucket_owner
, s
->canned_acl
);
2231 int get_data(buffer::list
& _bl
) override
{
2232 /* XXX for now, use sharing semantics */
2233 uint32_t len
= data
.length();
2235 bytes_written
+= len
;
2239 void put_data(off_t off
, buffer::list
& _bl
) {
2240 if (off
!= real_ofs
) {
2244 real_ofs
+= data
.length();
2245 ofs
= off
; /* consumed in exec_continue() */
2248 int exec_start() override
;
2249 int exec_continue() override
;
2250 int exec_finish() override
;
2252 void send_response() override
{}
2254 int verify_params() override
{
2257 }; /* RGWWriteRequest */
2262 class RGWCopyObjRequest
: public RGWLibRequest
,
2263 public RGWCopyObj
/* RGWOp */
2266 RGWFileHandle
* src_parent
;
2267 RGWFileHandle
* dst_parent
;
2268 const std::string
& src_name
;
2269 const std::string
& dst_name
;
2271 RGWCopyObjRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
2272 RGWFileHandle
* _src_parent
, RGWFileHandle
* _dst_parent
,
2273 const std::string
& _src_name
, const std::string
& _dst_name
)
2274 : RGWLibRequest(_cct
, _user
), src_parent(_src_parent
),
2275 dst_parent(_dst_parent
), src_name(_src_name
), dst_name(_dst_name
) {
2276 /* all requests have this */
2279 /* allow this request to replace selected attrs */
2280 attrs_mod
= RGWRados::ATTRSMOD_MERGE
;
2283 bool only_bucket() override
{ return true; }
2285 int op_init() override
{
2286 // assign store, s, and dialect_handler
2287 RGWObjectCtx
* rados_ctx
2288 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
2289 // framework promises to call op_init after parent init
2291 RGWOp::init(rados_ctx
->store
, get_state(), this);
2292 op
= this; // assign self as op: REQUIRED
2297 int header_init() override
{
2299 struct req_state
* s
= get_state();
2300 s
->info
.method
= "PUT"; // XXX check
2303 src_bucket_name
= src_parent
->bucket_name();
2304 // need s->src_bucket_name?
2305 src_object
.name
= src_parent
->format_child_name(src_name
);
2306 // need s->src_object?
2308 dest_bucket_name
= dst_parent
->bucket_name();
2309 // need s->bucket.name?
2310 dest_object
= dst_parent
->format_child_name(dst_name
);
2311 // need s->object_name?
2313 int rc
= valid_s3_object_name(dest_object
);
2317 /* XXX and fixup key attr (could optimize w/string ref and
2319 buffer::list ux_key
;
2320 std::string key_name
{dst_parent
->make_key_name(dst_name
.c_str())};
2321 fh_key fhk
= dst_parent
->make_fhk(key_name
);
2322 rgw::encode(fhk
, ux_key
);
2323 emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
2325 #if 0 /* XXX needed? */
2326 s
->relative_uri
= uri
;
2327 s
->info
.request_uri
= uri
; // XXX
2328 s
->info
.effective_uri
= uri
;
2329 s
->info
.request_params
= "";
2330 s
->info
.domain
= ""; /* XXX ? */
2339 int get_params() override
{
2340 struct req_state
* s
= get_state();
2341 RGWAccessControlPolicy_S3
s3policy(s
->cct
);
2342 /* we don't have (any) headers, so just create canned ACLs */
2343 int ret
= s3policy
.create_canned(s
->owner
, s
->bucket_owner
, s
->canned_acl
);
2344 dest_policy
= s3policy
;
2348 void send_response() override
{}
2349 void send_partial_response(off_t ofs
) override
{}
2351 }; /* RGWCopyObjRequest */
2353 class RGWSetAttrsRequest
: public RGWLibRequest
,
2354 public RGWSetAttrs
/* RGWOp */
2357 const std::string
& bucket_name
;
2358 const std::string
& obj_name
;
2360 RGWSetAttrsRequest(CephContext
* _cct
, RGWUserInfo
*_user
,
2361 const std::string
& _bname
, const std::string
& _oname
)
2362 : RGWLibRequest(_cct
, _user
), bucket_name(_bname
), obj_name(_oname
) {
2366 bool only_bucket() override
{ return false; }
2368 int op_init() override
{
2369 // assign store, s, and dialect_handler
2370 RGWObjectCtx
* rados_ctx
2371 = static_cast<RGWObjectCtx
*>(get_state()->obj_ctx
);
2372 // framework promises to call op_init after parent init
2374 RGWOp::init(rados_ctx
->store
, get_state(), this);
2375 op
= this; // assign self as op: REQUIRED
2379 int header_init() override
{
2381 struct req_state
* s
= get_state();
2382 s
->info
.method
= "PUT";
2385 /* XXX derp derp derp */
2386 std::string uri
= make_uri(bucket_name
, obj_name
);
2387 s
->relative_uri
= uri
;
2388 s
->info
.request_uri
= uri
; // XXX
2389 s
->info
.effective_uri
= uri
;
2390 s
->info
.request_params
= "";
2391 s
->info
.domain
= ""; /* XXX ? */
2399 int get_params() override
{
2403 void send_response() override
{}
2405 }; /* RGWSetAttrsRequest */
2407 } /* namespace rgw */
2409 #endif /* RGW_FILE_H */