1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/compat.h"
5 #include "include/rados/rgw_file.h"
11 #include "rgw_rados.h"
12 #include "rgw_resolve.h"
16 #include "rgw_acl_s3.h"
17 #include "rgw_frontend.h"
18 #include "rgw_request.h"
19 #include "rgw_process.h"
20 #include "rgw_rest_user.h"
21 #include "rgw_rest_s3.h"
22 #include "rgw_os_lib.h"
23 #include "rgw_auth_s3.h"
25 #include "rgw_bucket.h"
28 #include "rgw_lib_frontend.h"
32 #define dout_subsys ceph_subsys_rgw
40 const string
RGWFileHandle::root_name
= "/";
42 std::atomic
<uint32_t> RGWLibFS::fs_inst_counter
;
44 uint32_t RGWLibFS::write_completion_interval_s
= 10;
46 ceph::timer
<ceph::mono_clock
> RGWLibFS::write_timer
{
47 ceph::construct_suspended
};
49 inline int valid_fs_bucket_name(const string
& name
) {
50 int rc
= valid_s3_bucket_name(name
, false /* relaxed */);
52 if (name
.size() > 255)
59 inline int valid_fs_object_name(const string
& name
) {
60 int rc
= valid_s3_object_name(name
);
62 if (name
.size() > 1024)
69 LookupFHResult
RGWLibFS::stat_bucket(RGWFileHandle
* parent
, const char *path
,
70 RGWLibFS::BucketStats
& bs
,
73 LookupFHResult fhr
{nullptr, 0};
74 std::string bucket_name
{path
};
75 RGWStatBucketRequest
req(cct
, get_user(), bucket_name
, bs
);
77 int rc
= rgwlib
.get_fe()->execute_req(&req
);
79 (req
.get_ret() == 0) &&
81 fhr
= lookup_fh(parent
, path
,
82 (flags
& RGWFileHandle::FLAG_LOCKED
)|
83 RGWFileHandle::FLAG_CREATE
|
84 RGWFileHandle::FLAG_BUCKET
);
86 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
87 if (! (flags
& RGWFileHandle::FLAG_LOCKED
)) {
90 rgw_fh
->set_times(req
.get_ctime());
91 /* restore attributes */
92 auto ux_key
= req
.get_attr(RGW_ATTR_UNIX_KEY1
);
93 auto ux_attrs
= req
.get_attr(RGW_ATTR_UNIX1
);
94 if (ux_key
&& ux_attrs
) {
95 rgw_fh
->decode_attrs(ux_key
, ux_attrs
);
97 if (! (flags
& RGWFileHandle::FLAG_LOCKED
)) {
105 LookupFHResult
RGWLibFS::stat_leaf(RGWFileHandle
* parent
,
107 enum rgw_fh_type type
,
110 /* find either-of <object_name>, <object_name/>, only one of
111 * which should exist; atomicity? */
114 LookupFHResult fhr
{nullptr, 0};
116 /* XXX the need for two round-trip operations to identify file or
117 * directory leaf objects is unecessary--the current proposed
118 * mechanism to avoid this is to store leaf object names with an
119 * object locator w/o trailing slash */
121 std::string obj_path
= parent
->format_child_name(path
, false);
123 for (auto ix
: { 0, 1, 2 }) {
128 if (type
== RGW_FS_TYPE_DIRECTORY
)
131 RGWStatObjRequest
req(cct
, get_user(),
132 parent
->bucket_name(), obj_path
,
133 RGWStatObjRequest::FLAG_NONE
);
134 int rc
= rgwlib
.get_fe()->execute_req(&req
);
136 (req
.get_ret() == 0)) {
137 fhr
= lookup_fh(parent
, path
, RGWFileHandle::FLAG_CREATE
);
139 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
140 lock_guard
guard(rgw_fh
->mtx
);
141 rgw_fh
->set_size(req
.get_size());
142 rgw_fh
->set_times(req
.get_mtime());
143 /* restore attributes */
144 auto ux_key
= req
.get_attr(RGW_ATTR_UNIX_KEY1
);
145 auto ux_attrs
= req
.get_attr(RGW_ATTR_UNIX1
);
146 if (ux_key
&& ux_attrs
) {
147 rgw_fh
->decode_attrs(ux_key
, ux_attrs
);
158 if (type
== RGW_FS_TYPE_FILE
)
162 RGWStatObjRequest
req(cct
, get_user(),
163 parent
->bucket_name(), obj_path
,
164 RGWStatObjRequest::FLAG_NONE
);
165 int rc
= rgwlib
.get_fe()->execute_req(&req
);
167 (req
.get_ret() == 0)) {
168 fhr
= lookup_fh(parent
, path
, RGWFileHandle::FLAG_DIRECTORY
);
170 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
171 lock_guard
guard(rgw_fh
->mtx
);
172 rgw_fh
->set_size(req
.get_size());
173 rgw_fh
->set_times(req
.get_mtime());
174 /* restore attributes */
175 auto ux_key
= req
.get_attr(RGW_ATTR_UNIX_KEY1
);
176 auto ux_attrs
= req
.get_attr(RGW_ATTR_UNIX1
);
177 if (ux_key
&& ux_attrs
) {
178 rgw_fh
->decode_attrs(ux_key
, ux_attrs
);
187 std::string object_name
{path
};
188 RGWStatLeafRequest
req(cct
, get_user(), parent
, object_name
);
189 int rc
= rgwlib
.get_fe()->execute_req(&req
);
191 (req
.get_ret() == 0)) {
193 /* we need rgw object's key name equal to file name, if
195 if ((flags
& RGWFileHandle::FLAG_EXACT_MATCH
) &&
196 !req
.exact_matched
) {
197 lsubdout(get_context(), rgw
, 15)
199 << ": stat leaf not exact match file name = "
203 fhr
= lookup_fh(parent
, path
,
204 RGWFileHandle::FLAG_CREATE
|
206 RGWFileHandle::FLAG_DIRECTORY
:
207 RGWFileHandle::FLAG_NONE
));
208 /* XXX we don't have an object--in general, there need not
209 * be one (just a path segment in some other object). In
210 * actual leaf an object exists, but we'd need another round
211 * trip to get attrs */
213 /* for now use the parent object's mtime */
214 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
215 lock_guard
guard(rgw_fh
->mtx
);
216 rgw_fh
->set_mtime(parent
->get_mtime());
229 } /* RGWLibFS::stat_leaf */
231 int RGWLibFS::read(RGWFileHandle
* rgw_fh
, uint64_t offset
, size_t length
,
232 size_t* bytes_read
, void* buffer
, uint32_t flags
)
234 if (! rgw_fh
->is_file())
237 if (rgw_fh
->deleted())
240 RGWReadRequest
req(get_context(), get_user(), rgw_fh
, offset
, length
,
243 int rc
= rgwlib
.get_fe()->execute_req(&req
);
245 (req
.get_ret() == 0)) {
246 lock_guard(rgw_fh
->mtx
);
247 rgw_fh
->set_atime(real_clock::to_timespec(real_clock::now()));
248 *bytes_read
= req
.nread
;
254 int RGWLibFS::unlink(RGWFileHandle
* rgw_fh
, const char* name
, uint32_t flags
)
258 RGWFileHandle
* parent
= nullptr;
259 RGWFileHandle
* bkt_fh
= nullptr;
261 if (unlikely(flags
& RGWFileHandle::FLAG_UNLINK_THIS
)) {
263 parent
= rgw_fh
->get_parent();
267 LookupFHResult fhr
= lookup_fh(parent
, name
, RGWFileHandle::FLAG_LOCK
);
268 rgw_fh
= get
<0>(fhr
);
272 if (parent
->is_root()) {
273 /* a bucket may have an object storing Unix attributes, check
274 * for and delete it */
276 fhr
= stat_bucket(parent
, name
, bs
, (rgw_fh
) ?
277 RGWFileHandle::FLAG_LOCKED
:
278 RGWFileHandle::FLAG_NONE
);
279 bkt_fh
= get
<0>(fhr
);
280 if (unlikely(! bkt_fh
)) {
281 /* implies !rgw_fh, so also !LOCKED */
285 if (bs
.num_entries
> 1) {
286 unref(bkt_fh
); /* return stat_bucket ref */
287 if (likely(!! rgw_fh
)) { /* return lock and ref from
288 * lookup_fh (or caller in the
290 * RGWFileHandle::FLAG_UNLINK_THIS) */
291 rgw_fh
->mtx
.unlock();
296 /* delete object w/key "<bucket>/" (uxattrs), if any */
298 RGWDeleteObjRequest
req(cct
, get_user(), bkt_fh
->bucket_name(), oname
);
299 rc
= rgwlib
.get_fe()->execute_req(&req
);
300 /* don't care if ENOENT */
305 RGWDeleteBucketRequest
req(cct
, get_user(), bname
);
306 rc
= rgwlib
.get_fe()->execute_req(&req
);
315 /* XXX for now, peform a hard lookup to deduce the type of
316 * object to be deleted ("foo" vs. "foo/")--also, ensures
317 * atomicity at this endpoint */
318 struct rgw_file_handle
*fh
;
319 rc
= rgw_lookup(get_fs(), parent
->get_fh(), name
, &fh
,
320 RGW_LOOKUP_FLAG_NONE
);
325 rgw_fh
= get_rgwfh(fh
);
326 rgw_fh
->mtx
.lock(); /* LOCKED */
329 std::string oname
= rgw_fh
->relative_object_name();
330 if (rgw_fh
->is_dir()) {
331 /* for the duration of our cache timer, trust positive
333 if (rgw_fh
->has_children()) {
334 rgw_fh
->mtx
.unlock();
340 RGWDeleteObjRequest
req(cct
, get_user(), parent
->bucket_name(),
342 rc
= rgwlib
.get_fe()->execute_req(&req
);
348 /* ENOENT when raced with other s3 gateway */
349 if (! rc
|| rc
== -ENOENT
) {
350 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
351 fh_cache
.remove(rgw_fh
->fh
.fh_hk
.object
, rgw_fh
,
352 RGWFileHandle::FHCache::FLAG_LOCK
);
356 real_time t
= real_clock::now();
357 parent
->set_mtime(real_clock::to_timespec(t
));
358 parent
->set_ctime(real_clock::to_timespec(t
));
361 rgw_fh
->mtx
.unlock();
365 } /* RGWLibFS::unlink */
367 int RGWLibFS::rename(RGWFileHandle
* src_fh
, RGWFileHandle
* dst_fh
,
368 const char *_src_name
, const char *_dst_name
)
371 /* XXX initial implementation: try-copy, and delete if copy
377 std::string src_name
{_src_name
};
378 std::string dst_name
{_dst_name
};
381 LookupFHResult fhr
= lookup_fh(src_fh
, _src_name
, RGWFileHandle::FLAG_LOCK
);
382 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
384 /* should not happen */
386 ldout(get_context(), 0) << __func__
387 << " BUG no such src renaming path="
393 /* forbid renaming of directories (unreasonable at scale) */
394 if (rgw_fh
->is_dir()) {
395 ldout(get_context(), 12) << __func__
396 << " rejecting attempt to rename directory path="
397 << rgw_fh
->full_object_name()
403 /* forbid renaming open files (violates intent, for now) */
404 if (rgw_fh
->is_open()) {
405 ldout(get_context(), 12) << __func__
406 << " rejecting attempt to rename open file path="
407 << rgw_fh
->full_object_name()
413 t
= real_clock::now();
415 for (int ix
: {0, 1}) {
419 RGWCopyObjRequest
req(cct
, get_user(), src_fh
, dst_fh
, src_name
,
421 int rc
= rgwlib
.get_fe()->execute_req(&req
);
423 ((rc
= req
.get_ret()) != 0)) {
424 ldout(get_context(), 1)
426 << " rename step 0 failed src="
427 << src_fh
->full_object_name() << " " << src_name
428 << " dst=" << dst_fh
->full_object_name()
434 ldout(get_context(), 12)
436 << " rename step 0 success src="
437 << src_fh
->full_object_name() << " " << src_name
438 << " dst=" << dst_fh
->full_object_name()
442 /* update dst change id */
443 dst_fh
->set_times(t
);
448 rc
= this->unlink(rgw_fh
/* LOCKED */, _src_name
,
449 RGWFileHandle::FLAG_UNLINK_THIS
);
452 ldout(get_context(), 12)
454 << " rename step 1 success src="
455 << src_fh
->full_object_name() << " " << src_name
456 << " dst=" << dst_fh
->full_object_name()
460 /* update src change id */
461 src_fh
->set_times(t
);
463 ldout(get_context(), 1)
465 << " rename step 1 failed src="
466 << src_fh
->full_object_name() << " " << src_name
467 << " dst=" << dst_fh
->full_object_name()
479 rgw_fh
->mtx
.unlock(); /* !LOCKED */
480 unref(rgw_fh
); /* -ref */
484 } /* RGWLibFS::rename */
486 MkObjResult
RGWLibFS::mkdir(RGWFileHandle
* parent
, const char *name
,
487 struct stat
*st
, uint32_t mask
, uint32_t flags
)
490 rgw_file_handle
*lfh
;
492 rc
= rgw_lookup(get_fs(), parent
->get_fh(), name
, &lfh
,
493 RGW_LOOKUP_FLAG_NONE
);
496 rc
= rgw_fh_rele(get_fs(), lfh
, RGW_FH_RELE_FLAG_NONE
);
497 return MkObjResult
{nullptr, -EEXIST
};
500 MkObjResult mkr
{nullptr, -EINVAL
};
502 RGWFileHandle
* rgw_fh
= nullptr;
503 buffer::list ux_key
, ux_attrs
;
505 fhr
= lookup_fh(parent
, name
,
506 RGWFileHandle::FLAG_CREATE
|
507 RGWFileHandle::FLAG_DIRECTORY
|
508 RGWFileHandle::FLAG_LOCK
);
509 rgw_fh
= get
<0>(fhr
);
511 rgw_fh
->create_stat(st
, mask
);
512 rgw_fh
->set_times(real_clock::now());
514 rgw_fh
->encode_attrs(ux_key
, ux_attrs
);
517 get
<0>(mkr
) = rgw_fh
;
523 if (parent
->is_root()) {
526 /* enforce S3 name restrictions */
527 rc
= valid_fs_bucket_name(bname
);
529 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
530 fh_cache
.remove(rgw_fh
->fh
.fh_hk
.object
, rgw_fh
,
531 RGWFileHandle::FHCache::FLAG_LOCK
);
532 rgw_fh
->mtx
.unlock();
534 get
<0>(mkr
) = nullptr;
539 RGWCreateBucketRequest
req(get_context(), get_user(), bname
);
542 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
543 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
545 rc
= rgwlib
.get_fe()->execute_req(&req
);
548 /* create an object representing the directory */
550 string dir_name
= parent
->format_child_name(name
, true);
552 /* need valid S3 name (characters, length <= 1024, etc) */
553 rc
= valid_fs_object_name(dir_name
);
555 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
556 fh_cache
.remove(rgw_fh
->fh
.fh_hk
.object
, rgw_fh
,
557 RGWFileHandle::FHCache::FLAG_LOCK
);
558 rgw_fh
->mtx
.unlock();
560 get
<0>(mkr
) = nullptr;
565 RGWPutObjRequest
req(get_context(), get_user(), parent
->bucket_name(),
569 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
570 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
572 rc
= rgwlib
.get_fe()->execute_req(&req
);
579 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
580 rgw_fh
->mtx
.unlock(); /* !LOCKED */
582 get
<0>(mkr
) = nullptr;
587 real_time t
= real_clock::now();
588 parent
->set_mtime(real_clock::to_timespec(t
));
589 parent
->set_ctime(real_clock::to_timespec(t
));
590 rgw_fh
->mtx
.unlock(); /* !LOCKED */
596 } /* RGWLibFS::mkdir */
598 MkObjResult
RGWLibFS::create(RGWFileHandle
* parent
, const char *name
,
599 struct stat
*st
, uint32_t mask
, uint32_t flags
)
605 rgw_file_handle
*lfh
;
606 rc
= rgw_lookup(get_fs(), parent
->get_fh(), name
, &lfh
,
607 RGW_LOOKUP_FLAG_NONE
);
610 rc
= rgw_fh_rele(get_fs(), lfh
, RGW_FH_RELE_FLAG_NONE
);
611 return MkObjResult
{nullptr, -EEXIST
};
614 /* expand and check name */
615 std::string obj_name
= parent
->format_child_name(name
, false);
616 rc
= valid_fs_object_name(obj_name
);
618 return MkObjResult
{nullptr, rc
};
623 RGWPutObjRequest
req(cct
, get_user(), parent
->bucket_name(), obj_name
, bl
);
624 MkObjResult mkr
{nullptr, -EINVAL
};
626 rc
= rgwlib
.get_fe()->execute_req(&req
);
632 LookupFHResult fhr
= lookup_fh(parent
, name
, RGWFileHandle::FLAG_CREATE
|
633 RGWFileHandle::FLAG_LOCK
);
634 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
636 if (get
<1>(fhr
) & RGWFileHandle::FLAG_CREATE
) {
637 /* fill in stat data */
638 real_time t
= real_clock::now();
639 rgw_fh
->create_stat(st
, mask
);
640 rgw_fh
->set_times(t
);
642 parent
->set_mtime(real_clock::to_timespec(t
));
643 parent
->set_ctime(real_clock::to_timespec(t
));
646 (void) rgw_fh
->stat(st
);
647 get
<0>(mkr
) = rgw_fh
;
648 rgw_fh
->mtx
.unlock();
656 } /* RGWLibFS::create */
658 int RGWLibFS::getattr(RGWFileHandle
* rgw_fh
, struct stat
* st
)
660 switch(rgw_fh
->fh
.fh_type
) {
661 case RGW_FS_TYPE_FILE
:
663 if (rgw_fh
->deleted())
671 return rgw_fh
->stat(st
);
672 } /* RGWLibFS::getattr */
674 int RGWLibFS::setattr(RGWFileHandle
* rgw_fh
, struct stat
* st
, uint32_t mask
,
678 buffer::list ux_key
, ux_attrs
;
680 lock_guard
guard(rgw_fh
->mtx
);
682 switch(rgw_fh
->fh
.fh_type
) {
683 case RGW_FS_TYPE_FILE
:
685 if (rgw_fh
->deleted())
693 string obj_name
{rgw_fh
->relative_object_name()};
695 if (rgw_fh
->is_dir() &&
696 (likely(! rgw_fh
->is_bucket()))) {
700 RGWSetAttrsRequest
req(cct
, get_user(), rgw_fh
->bucket_name(), obj_name
);
702 rgw_fh
->create_stat(st
, mask
);
703 rgw_fh
->encode_attrs(ux_key
, ux_attrs
);
706 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
707 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
709 rc
= rgwlib
.get_fe()->execute_req(&req
);
713 /* special case: materialize placeholder dir */
715 RGWPutObjRequest
req(get_context(), get_user(), rgw_fh
->bucket_name(),
718 rgw_fh
->encode_attrs(ux_key
, ux_attrs
); /* because std::moved */
721 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
722 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
724 rc
= rgwlib
.get_fe()->execute_req(&req
);
728 if ((rc
!= 0) || (rc2
!= 0)) {
732 rgw_fh
->set_ctime(real_clock::to_timespec(real_clock::now()));
735 } /* RGWLibFS::setattr */
737 void RGWLibFS::close()
739 state
.flags
|= FLAG_CLOSED
;
745 ObjUnref(RGWLibFS
* fs
) : fs(fs
) {}
746 void operator()(RGWFileHandle
* fh
) const {
747 lsubdout(fs
->get_context(), rgw
, 5)
750 << " before ObjUnref refs=" << fh
->get_refcnt()
756 /* force cache drain, forces objects to evict */
757 fh_cache
.drain(ObjUnref(this),
758 RGWFileHandle::FHCache::FLAG_LOCK
);
759 rgwlib
.get_fe()->get_process()->unregister_fs(this);
761 } /* RGWLibFS::close */
763 inline std::ostream
& operator<<(std::ostream
&os
, struct timespec
const &ts
) {
764 os
<< "<timespec: tv_sec=";
772 std::ostream
& operator<<(std::ostream
&os
, RGWLibFS::event
const &ev
) {
775 case RGWLibFS::event::type::READDIR
:
776 os
<< "type=READDIR;";
779 os
<< "type=UNKNOWN;";
782 os
<< "fid=" << ev
.fhk
.fh_hk
.bucket
<< ":" << ev
.fhk
.fh_hk
.object
783 << ";ts=" << ev
.ts
<< ">";
790 using directory
= RGWFileHandle::directory
;
792 /* dirent invalidate timeout--basically, the upper-bound on
793 * inconsistency with the S3 namespace */
795 = get_context()->_conf
->rgw_nfs_namespace_expire_secs
;
797 /* max events to gc in one cycle */
799 std::max(1, get_context()->_conf
->rgw_nfs_max_gc
);
801 struct timespec now
, expire_ts
;
804 std::deque
<event
> &events
= state
.events
;
807 (void) clock_gettime(CLOCK_MONOTONIC_COARSE
, &now
);
808 lsubdout(get_context(), rgw
, 15)
809 << "GC: top of expire loop"
811 << " expire_s=" << expire_s
814 lock_guard
guard(state
.mtx
); /* LOCKED */
815 /* just return if no events */
816 if (events
.empty()) {
820 (events
.size() < 500) ? max_ev
: (events
.size() / 4);
821 for (uint32_t ix
= 0; (ix
< _max_ev
) && (events
.size() > 0); ++ix
) {
822 event
& ev
= events
.front();
824 expire_ts
.tv_sec
+= expire_s
;
825 if (expire_ts
> now
) {
834 for (auto& ev
: ve
) {
835 lsubdout(get_context(), rgw
, 15)
836 << "try-expire ev: " << ev
<< dendl
;
837 if (likely(ev
.t
== event::type::READDIR
)) {
838 RGWFileHandle
* rgw_fh
= lookup_handle(ev
.fhk
.fh_hk
);
839 lsubdout(get_context(), rgw
, 15)
840 << "ev rgw_fh: " << rgw_fh
<< dendl
;
842 RGWFileHandle::directory
* d
;
843 if (unlikely(! rgw_fh
->is_dir())) {
844 lsubdout(get_context(), rgw
, 0)
846 << " BUG non-directory found with READDIR event "
847 << "(" << rgw_fh
->bucket_name() << ","
848 << rgw_fh
->object_name() << ")"
852 /* maybe clear state */
853 d
= get
<directory
>(&rgw_fh
->variant_type
);
855 struct timespec ev_ts
= ev
.ts
;
856 lock_guard
guard(rgw_fh
->mtx
);
857 struct timespec d_last_readdir
= d
->last_readdir
;
858 if (unlikely(ev_ts
< d_last_readdir
)) {
859 /* readdir cycle in progress, don't invalidate */
860 lsubdout(get_context(), rgw
, 15)
861 << "GC: delay expiration for "
862 << rgw_fh
->object_name()
863 << " ev.ts=" << ev_ts
864 << " last_readdir=" << d_last_readdir
868 lsubdout(get_context(), rgw
, 15)
870 << rgw_fh
->object_name()
872 rgw_fh
->clear_state();
873 rgw_fh
->invalidate();
879 } /* event::type::READDIR */
882 } while (! (stop
|| shutdown
));
885 std::ostream
& operator<<(std::ostream
&os
,
886 RGWFileHandle
const &rgw_fh
)
888 const auto& fhk
= rgw_fh
.get_key();
889 const auto& fh
= const_cast<RGWFileHandle
&>(rgw_fh
).get_fh();
890 os
<< "<RGWFileHandle:";
891 os
<< "addr=" << &rgw_fh
<< ";";
892 switch (fh
->fh_type
) {
893 case RGW_FS_TYPE_DIRECTORY
:
894 os
<< "type=DIRECTORY;";
896 case RGW_FS_TYPE_FILE
:
900 os
<< "type=UNKNOWN;";
903 os
<< "fid=" << fhk
.fh_hk
.bucket
<< ":" << fhk
.fh_hk
.object
<< ";";
904 os
<< "name=" << rgw_fh
.object_name() << ";";
905 os
<< "refcnt=" << rgw_fh
.get_refcnt() << ";";
910 RGWFileHandle::~RGWFileHandle() {
911 /* in the non-delete case, handle may still be in handle table */
912 if (fh_hook
.is_linked()) {
913 fs
->fh_cache
.remove(fh
.fh_hk
.object
, this, FHCache::FLAG_LOCK
);
915 /* cond-unref parent */
916 if (parent
&& (! parent
->is_root())) {
917 /* safe because if parent->unref causes its deletion,
918 * there are a) by refcnt, no other objects/paths pointing
919 * to it and b) by the semantics of valid iteration of
920 * fh_lru (observed, e.g., by cohort_lru<T,...>::drain())
921 * no unsafe iterators reaching it either--n.b., this constraint
922 * is binding oncode which may in future attempt to e.g.,
923 * cause the eviction of objects in LRU order */
924 (void) get_fs()->unref(parent
);
928 void RGWFileHandle::encode_attrs(ceph::buffer::list
& ux_key1
,
929 ceph::buffer::list
& ux_attrs1
)
931 fh_key
fhk(this->fh
.fh_hk
);
932 rgw::encode(fhk
, ux_key1
);
933 rgw::encode(*this, ux_attrs1
);
934 } /* RGWFileHandle::encode_attrs */
936 void RGWFileHandle::decode_attrs(const ceph::buffer::list
* ux_key1
,
937 const ceph::buffer::list
* ux_attrs1
)
940 auto bl_iter_key1
= const_cast<buffer::list
*>(ux_key1
)->begin();
941 rgw::decode(fhk
, bl_iter_key1
);
942 assert(this->fh
.fh_hk
== fhk
.fh_hk
);
944 auto bl_iter_unix1
= const_cast<buffer::list
*>(ux_attrs1
)->begin();
945 rgw::decode(*this, bl_iter_unix1
);
946 } /* RGWFileHandle::decode_attrs */
948 bool RGWFileHandle::reclaim() {
949 lsubdout(fs
->get_context(), rgw
, 17)
950 << __func__
<< " " << *this
952 /* remove if still in fh_cache */
953 if (fh_hook
.is_linked()) {
954 fs
->fh_cache
.remove(fh
.fh_hk
.object
, this, FHCache::FLAG_LOCK
);
957 } /* RGWFileHandle::reclaim */
959 bool RGWFileHandle::has_children() const
961 if (unlikely(! is_dir()))
964 RGWRMdirCheck
req(fs
->get_context(), fs
->get_user(), this);
965 int rc
= rgwlib
.get_fe()->execute_req(&req
);
967 return req
.valid
&& req
.has_children
;
973 int RGWFileHandle::readdir(rgw_readdir_cb rcb
, void *cb_arg
, uint64_t *offset
,
974 bool *eof
, uint32_t flags
)
976 using event
= RGWLibFS::event
;
979 CephContext
* cct
= fs
->get_context();
981 if ((*offset
== 0) &&
982 (flags
& RGW_READDIR_FLAG_DOTDOT
)) {
983 /* send '.' and '..' with their NFS-defined offsets */
984 rcb(".", cb_arg
, 1, RGW_LOOKUP_FLAG_DIR
);
985 rcb("..", cb_arg
, 2, RGW_LOOKUP_FLAG_DIR
);
988 lsubdout(fs
->get_context(), rgw
, 15)
990 << " offset=" << *offset
993 directory
* d
= get
<directory
>(&variant_type
);
995 (void) clock_gettime(CLOCK_MONOTONIC_COARSE
, &now
); /* !LOCKED */
996 lock_guard
guard(mtx
);
997 d
->last_readdir
= now
;
1001 RGWListBucketsRequest
req(cct
, fs
->get_user(), this, rcb
, cb_arg
,
1003 rc
= rgwlib
.get_fe()->execute_req(&req
);
1005 (void) clock_gettime(CLOCK_MONOTONIC_COARSE
, &now
); /* !LOCKED */
1006 lock_guard
guard(mtx
);
1010 inc_nlink(req
.d_count
);
1012 event
ev(event::type::READDIR
, get_key(), state
.atime
);
1013 lock_guard
sguard(fs
->state
.mtx
);
1014 fs
->state
.push_event(ev
);
1017 RGWReaddirRequest
req(cct
, fs
->get_user(), this, rcb
, cb_arg
, offset
);
1018 rc
= rgwlib
.get_fe()->execute_req(&req
);
1020 (void) clock_gettime(CLOCK_MONOTONIC_COARSE
, &now
); /* !LOCKED */
1021 lock_guard
guard(mtx
);
1025 inc_nlink(req
.d_count
);
1027 event
ev(event::type::READDIR
, get_key(), state
.atime
);
1028 lock_guard
sguard(fs
->state
.mtx
);
1029 fs
->state
.push_event(ev
);
1033 lsubdout(fs
->get_context(), rgw
, 15)
1035 << " final link count=" << state
.nlink
1039 } /* RGWFileHandle::readdir */
1041 int RGWFileHandle::write(uint64_t off
, size_t len
, size_t *bytes_written
,
1045 using WriteCompletion
= RGWLibFS::WriteCompletion
;
1047 lock_guard
guard(mtx
);
1051 file
* f
= get
<file
>(&variant_type
);
1056 lsubdout(fs
->get_context(), rgw
, 5)
1058 << " write attempted on deleted object "
1059 << this->object_name()
1061 /* zap write transaction, if any */
1063 delete f
->write_req
;
1064 f
->write_req
= nullptr;
1069 if (! f
->write_req
) {
1070 /* guard--we do not support (e.g., COW-backed) partial writes */
1072 lsubdout(fs
->get_context(), rgw
, 5)
1074 << " " << object_name()
1075 << " non-0 initial write position " << off
1081 std::string object_name
= relative_object_name();
1083 new RGWWriteRequest(fs
->get_context(), fs
->get_user(), this,
1084 bucket_name(), object_name
);
1085 rc
= rgwlib
.get_fe()->start_req(f
->write_req
);
1087 lsubdout(fs
->get_context(), rgw
, 5)
1089 << this->object_name()
1090 << " write start failed " << off
1091 << " (" << rc
<< ")"
1093 /* zap failed write transaction */
1094 delete f
->write_req
;
1095 f
->write_req
= nullptr;
1098 if (stateless_open()) {
1099 /* start write timer */
1100 f
->write_req
->timer_id
=
1101 RGWLibFS::write_timer
.add_event(
1102 std::chrono::seconds(RGWLibFS::write_completion_interval_s
),
1103 WriteCompletion(*this));
1112 buffer::create_static(len
, static_cast<char*>(buffer
)));
1115 buffer::copy(static_cast<char*>(buffer
), len
));
1118 f
->write_req
->put_data(off
, bl
);
1119 rc
= f
->write_req
->exec_continue();
1122 size_t min_size
= off
+ len
;
1123 if (min_size
> get_size())
1125 if (stateless_open()) {
1126 /* bump write timer */
1127 RGWLibFS::write_timer
.adjust_event(
1128 f
->write_req
->timer_id
, std::chrono::seconds(10));
1131 /* continuation failed (e.g., non-contiguous write position) */
1132 lsubdout(fs
->get_context(), rgw
, 5)
1135 << " failed write at position " << off
1136 << " (fails write transaction) "
1138 /* zap failed write transaction */
1139 delete f
->write_req
;
1140 f
->write_req
= nullptr;
1144 *bytes_written
= (rc
== 0) ? len
: 0;
1146 } /* RGWFileHandle::write */
1148 int RGWFileHandle::write_finish(uint32_t flags
)
1150 unique_lock guard
{mtx
, std::defer_lock
};
1153 if (! (flags
& FLAG_LOCKED
)) {
1157 file
* f
= get
<file
>(&variant_type
);
1158 if (f
&& (f
->write_req
)) {
1159 lsubdout(fs
->get_context(), rgw
, 10)
1161 << " finishing write trans on " << object_name()
1163 rc
= rgwlib
.get_fe()->finish_req(f
->write_req
);
1165 rc
= f
->write_req
->get_ret();
1167 delete f
->write_req
;
1168 f
->write_req
= nullptr;
1172 } /* RGWFileHandle::write_finish */
1174 int RGWFileHandle::close()
1176 lock_guard
guard(mtx
);
1178 int rc
= write_finish(FLAG_LOCKED
);
1180 flags
&= ~FLAG_OPEN
;
1181 flags
&= ~FLAG_STATELESS_OPEN
;
1184 } /* RGWFileHandle::close */
1186 RGWFileHandle::file::~file()
1191 void RGWFileHandle::clear_state()
1193 directory
* d
= get
<directory
>(&variant_type
);
1196 d
->last_marker
= rgw_obj_key
{};
1200 void RGWFileHandle::invalidate() {
1201 RGWLibFS
*fs
= get_fs();
1202 if (fs
->invalidate_cb
) {
1203 fs
->invalidate_cb(fs
->invalidate_arg
, get_key().fh_hk
);
1207 int RGWWriteRequest::exec_start() {
1208 struct req_state
* s
= get_state();
1210 /* not obviously supportable */
1211 assert(! dlo_manifest
);
1214 perfcounter
->inc(l_rgw_put
);
1217 if (s
->object
.empty()) {
1218 ldout(s
->cct
, 0) << __func__
<< " called on empty object" << dendl
;
1222 op_ret
= get_params();
1226 op_ret
= get_system_versioning_params(s
, &olh_epoch
, &version_id
);
1231 /* user-supplied MD5 check skipped (not supplied) */
1232 /* early quota check skipped--we don't have size yet */
1233 /* skipping user-supplied etag--we might have one in future, but
1234 * like data it and other attrs would arrive after open */
1235 processor
= select_processor(*static_cast<RGWObjectCtx
*>(s
->obj_ctx
),
1237 op_ret
= processor
->prepare(get_store(), NULL
);
1243 int RGWWriteRequest::exec_continue()
1245 struct req_state
* s
= get_state();
1248 /* check guards (e.g., contig write) */
1252 size_t len
= data
.length();
1256 /* XXX we are currently synchronous--supplied data buffers cannot
1257 * be used after the caller returns */
1258 bool need_to_wait
= true;
1259 bufferlist orig_data
;
1264 hash
.Update((const byte
*)data
.c_str(), data
.length());
1265 op_ret
= put_data_and_throttle(processor
, data
, ofs
,
1268 if (!need_to_wait
|| op_ret
!= -EEXIST
) {
1269 ldout(s
->cct
, 20) << "processor->thottle_data() returned ret="
1274 ldout(s
->cct
, 5) << "NOTICE: processor->throttle_data() returned -EEXIST, need to restart write" << dendl
;
1276 /* restore original data */
1277 data
.swap(orig_data
);
1279 /* restart processing with different oid suffix */
1280 dispose_processor(processor
);
1281 processor
= select_processor(*static_cast<RGWObjectCtx
*>(s
->obj_ctx
),
1286 gen_rand_alphanumeric(get_store()->ctx(), buf
, sizeof(buf
) - 1);
1287 oid_rand
.append(buf
);
1289 op_ret
= processor
->prepare(get_store(), &oid_rand
);
1291 ldout(s
->cct
, 0) << "ERROR: processor->prepare() returned "
1296 op_ret
= put_data_and_throttle(processor
, data
, ofs
, false);
1301 bytes_written
+= len
;
1305 } /* exec_continue */
1307 int RGWWriteRequest::exec_finish()
1309 buffer::list bl
, aclbl
, ux_key
, ux_attrs
;
1310 map
<string
, string
>::iterator iter
;
1311 char calc_md5
[CEPH_CRYPTO_MD5_DIGESTSIZE
* 2 + 1];
1312 unsigned char m
[CEPH_CRYPTO_MD5_DIGESTSIZE
];
1313 struct req_state
* s
= get_state();
1315 size_t osize
= rgw_fh
->get_size();
1316 struct timespec octime
= rgw_fh
->get_ctime();
1317 struct timespec omtime
= rgw_fh
->get_mtime();
1318 real_time appx_t
= real_clock::now();
1320 s
->obj_size
= ofs
; // XXX check ofs
1321 perfcounter
->inc(l_rgw_put_b
, s
->obj_size
);
1323 op_ret
= get_store()->check_quota(s
->bucket_owner
.get_id(), s
->bucket
,
1324 user_quota
, bucket_quota
, s
->obj_size
);
1329 op_ret
= get_store()->check_bucket_shards(s
->bucket_info
, s
->bucket
, bucket_quota
);
1336 buf_to_hex(m
, CEPH_CRYPTO_MD5_DIGESTSIZE
, calc_md5
);
1339 bl
.append(etag
.c_str(), etag
.size() + 1);
1340 emplace_attr(RGW_ATTR_ETAG
, std::move(bl
));
1342 policy
.encode(aclbl
);
1343 emplace_attr(RGW_ATTR_ACL
, std::move(aclbl
));
1346 rgw_fh
->set_mtime(real_clock::to_timespec(appx_t
));
1347 rgw_fh
->set_ctime(real_clock::to_timespec(appx_t
));
1348 rgw_fh
->set_size(bytes_written
);
1349 rgw_fh
->encode_attrs(ux_key
, ux_attrs
);
1351 emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
1352 emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
1354 for (iter
= s
->generic_attrs
.begin(); iter
!= s
->generic_attrs
.end();
1356 buffer::list
& attrbl
= attrs
[iter
->first
];
1357 const string
& val
= iter
->second
;
1358 attrbl
.append(val
.c_str(), val
.size() + 1);
1361 rgw_get_request_metadata(s
->cct
, s
->info
, attrs
);
1362 encode_delete_at_attr(delete_at
, attrs
);
1364 /* Add a custom metadata to expose the information whether an object
1365 * is an SLO or not. Appending the attribute must be performed AFTER
1366 * processing any input from user in order to prohibit overwriting. */
1367 if (unlikely(!! slo_info
)) {
1368 buffer::list slo_userindicator_bl
;
1369 ::encode("True", slo_userindicator_bl
);
1370 emplace_attr(RGW_ATTR_SLO_UINDICATOR
, std::move(slo_userindicator_bl
));
1373 op_ret
= processor
->complete(s
->obj_size
, etag
, &mtime
, real_time(), attrs
,
1374 (delete_at
? *delete_at
: real_time()),
1375 if_match
, if_nomatch
);
1377 /* revert attr updates */
1378 rgw_fh
->set_mtime(omtime
);
1379 rgw_fh
->set_ctime(octime
);
1380 rgw_fh
->set_size(osize
);
1384 dispose_processor(processor
);
1385 perfcounter
->tinc(l_rgw_put_lat
,
1386 (ceph_clock_now() - s
->time
));
1390 } /* namespace rgw */
1395 void rgwfile_version(int *major
, int *minor
, int *extra
)
1398 *major
= LIBRGW_FILE_VER_MAJOR
;
1400 *minor
= LIBRGW_FILE_VER_MINOR
;
1402 *extra
= LIBRGW_FILE_VER_EXTRA
;
1406 attach rgw namespace
1408 int rgw_mount(librgw_t rgw
, const char *uid
, const char *acc_key
,
1409 const char *sec_key
, struct rgw_fs
**rgw_fs
,
1414 /* stash access data for "mount" */
1415 RGWLibFS
* new_fs
= new RGWLibFS(static_cast<CephContext
*>(rgw
), uid
, acc_key
,
1419 rc
= new_fs
->authorize(rgwlib
.get_store());
1425 /* register fs for shared gc */
1426 rgwlib
.get_fe()->get_process()->register_fs(new_fs
);
1428 struct rgw_fs
*fs
= new_fs
->get_fs();
1431 /* XXX we no longer assume "/" is unique, but we aren't tracking the
1440 register invalidate callbacks
1442 int rgw_register_invalidate(struct rgw_fs
*rgw_fs
, rgw_fh_callback_t cb
,
1443 void *arg
, uint32_t flags
)
1446 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1447 return fs
->register_invalidate(cb
, arg
, flags
);
1451 detach rgw namespace
1453 int rgw_umount(struct rgw_fs
*rgw_fs
, uint32_t flags
)
1455 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1461 get filesystem attributes
1463 int rgw_statfs(struct rgw_fs
*rgw_fs
,
1464 struct rgw_file_handle
*parent_fh
,
1465 struct rgw_statvfs
*vfs_st
, uint32_t flags
)
1467 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1469 /* XXX for now, just publish a huge capacity and
1470 * limited utiliztion */
1471 vfs_st
->f_bsize
= 1024*1024 /* 1M */;
1472 vfs_st
->f_frsize
= 1024; /* minimal allocation unit (who cares) */
1473 vfs_st
->f_blocks
= UINT64_MAX
;
1474 vfs_st
->f_bfree
= UINT64_MAX
;
1475 vfs_st
->f_bavail
= UINT64_MAX
;
1476 vfs_st
->f_files
= 1024; /* object count, do we have an est? */
1477 vfs_st
->f_ffree
= UINT64_MAX
;
1478 vfs_st
->f_fsid
[0] = fs
->get_inst();
1479 vfs_st
->f_fsid
[1] = fs
->get_inst();
1481 vfs_st
->f_namemax
= 4096;
1486 generic create -- create an empty regular file
1488 int rgw_create(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*parent_fh
,
1489 const char *name
, struct stat
*st
, uint32_t mask
,
1490 struct rgw_file_handle
**fh
, uint32_t posix_flags
,
1495 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1496 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
1499 (parent
->is_root()) ||
1500 (parent
->is_file())) {
1505 MkObjResult fhr
= fs
->create(parent
, name
, st
, mask
, flags
);
1506 RGWFileHandle
*nfh
= get
<0>(fhr
); // nullptr if !success
1509 *fh
= nfh
->get_fh();
1515 create a new directory
1517 int rgw_mkdir(struct rgw_fs
*rgw_fs
,
1518 struct rgw_file_handle
*parent_fh
,
1519 const char *name
, struct stat
*st
, uint32_t mask
,
1520 struct rgw_file_handle
**fh
, uint32_t flags
)
1524 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1525 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
1532 MkObjResult fhr
= fs
->mkdir(parent
, name
, st
, mask
, flags
);
1533 RGWFileHandle
*nfh
= get
<0>(fhr
); // nullptr if !success
1536 *fh
= nfh
->get_fh();
1544 int rgw_rename(struct rgw_fs
*rgw_fs
,
1545 struct rgw_file_handle
*src
, const char* src_name
,
1546 struct rgw_file_handle
*dst
, const char* dst_name
,
1549 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1551 RGWFileHandle
* src_fh
= get_rgwfh(src
);
1552 RGWFileHandle
* dst_fh
= get_rgwfh(dst
);
1554 return fs
->rename(src_fh
, dst_fh
, src_name
, dst_name
);
1558 remove file or directory
1560 int rgw_unlink(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*parent_fh
,
1561 const char *name
, uint32_t flags
)
1563 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1564 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
1566 return fs
->unlink(parent
, name
);
1570 lookup object by name (POSIX style)
1572 int rgw_lookup(struct rgw_fs
*rgw_fs
,
1573 struct rgw_file_handle
*parent_fh
, const char* path
,
1574 struct rgw_file_handle
**fh
, uint32_t flags
)
1576 //CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
1577 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1579 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
1581 (! parent
->is_dir())) {
1586 RGWFileHandle
* rgw_fh
;
1589 if (parent
->is_root()) {
1590 /* special: parent lookup--note lack of ref()! */
1591 if (unlikely((strcmp(path
, "..") == 0) ||
1592 (strcmp(path
, "/") == 0))) {
1595 RGWLibFS::BucketStats bstat
;
1596 fhr
= fs
->stat_bucket(parent
, path
, bstat
, RGWFileHandle::FLAG_NONE
);
1597 rgw_fh
= get
<0>(fhr
);
1602 /* lookup in a readdir callback */
1603 enum rgw_fh_type fh_type
= fh_type_of(flags
);
1605 uint32_t sl_flags
= (flags
& RGW_LOOKUP_FLAG_RCB
)
1606 ? RGWFileHandle::FLAG_NONE
1607 : RGWFileHandle::FLAG_EXACT_MATCH
;
1609 fhr
= fs
->stat_leaf(parent
, path
, fh_type
, sl_flags
);
1610 if (! get
<0>(fhr
)) {
1611 if (! (flags
& RGW_LOOKUP_FLAG_CREATE
))
1614 fhr
= fs
->lookup_fh(parent
, path
, RGWFileHandle::FLAG_CREATE
);
1616 rgw_fh
= get
<0>(fhr
);
1619 struct rgw_file_handle
*rfh
= rgw_fh
->get_fh();
1626 lookup object by handle (NFS style)
1628 int rgw_lookup_handle(struct rgw_fs
*rgw_fs
, struct rgw_fh_hk
*fh_hk
,
1629 struct rgw_file_handle
**fh
, uint32_t flags
)
1631 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1633 RGWFileHandle
* rgw_fh
= fs
->lookup_handle(*fh_hk
);
1639 struct rgw_file_handle
*rfh
= rgw_fh
->get_fh();
1646 * release file handle
1648 int rgw_fh_rele(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
1651 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1652 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1654 lsubdout(fs
->get_context(), rgw
, 17)
1655 << __func__
<< " " << *rgw_fh
1663 get unix attributes for object
1665 int rgw_getattr(struct rgw_fs
*rgw_fs
,
1666 struct rgw_file_handle
*fh
, struct stat
*st
, uint32_t flags
)
1668 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1669 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1671 return fs
->getattr(rgw_fh
, st
);
1675 set unix attributes for object
1677 int rgw_setattr(struct rgw_fs
*rgw_fs
,
1678 struct rgw_file_handle
*fh
, struct stat
*st
,
1679 uint32_t mask
, uint32_t flags
)
1681 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1682 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1684 return fs
->setattr(rgw_fh
, st
, mask
, flags
);
1690 int rgw_truncate(struct rgw_fs
*rgw_fs
,
1691 struct rgw_file_handle
*fh
, uint64_t size
, uint32_t flags
)
1699 int rgw_open(struct rgw_fs
*rgw_fs
,
1700 struct rgw_file_handle
*fh
, uint32_t posix_flags
, uint32_t flags
)
1702 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1705 * need to track specific opens--at least read opens and
1706 * a write open; we need to know when a write open is returned,
1707 * that closes a write transaction
1709 * for now, we will support single-open only, it's preferable to
1710 * anything we can otherwise do without access to the NFS state
1712 if (! rgw_fh
->is_file())
1715 return rgw_fh
->open(flags
);
1721 int rgw_close(struct rgw_fs
*rgw_fs
,
1722 struct rgw_file_handle
*fh
, uint32_t flags
)
1724 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1725 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1726 int rc
= rgw_fh
->close(/* XXX */);
1728 if (flags
& RGW_CLOSE_FLAG_RELE
)
1734 int rgw_readdir(struct rgw_fs
*rgw_fs
,
1735 struct rgw_file_handle
*parent_fh
, uint64_t *offset
,
1736 rgw_readdir_cb rcb
, void *cb_arg
, bool *eof
,
1739 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
1744 int rc
= parent
->readdir(rcb
, cb_arg
, offset
, eof
, flags
);
1751 int rgw_read(struct rgw_fs
*rgw_fs
,
1752 struct rgw_file_handle
*fh
, uint64_t offset
,
1753 size_t length
, size_t *bytes_read
, void *buffer
,
1756 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1757 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1759 return fs
->read(rgw_fh
, offset
, length
, bytes_read
, buffer
, flags
);
1765 int rgw_write(struct rgw_fs
*rgw_fs
,
1766 struct rgw_file_handle
*fh
, uint64_t offset
,
1767 size_t length
, size_t *bytes_written
, void *buffer
,
1770 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1775 if (! rgw_fh
->is_file())
1778 if (! rgw_fh
->is_open())
1781 rc
= rgw_fh
->write(offset
, length
, bytes_written
, buffer
);
1787 read data from file (vector)
1792 struct rgw_vio
* vio
;
1795 RGWReadV(buffer::list
& _bl
, rgw_vio
* _vio
) : vio(_vio
) {
1799 struct rgw_vio
* get_vio() { return vio
; }
1801 const std::list
<buffer::ptr
>& buffers() { return bl
.buffers(); }
1803 unsigned /* XXX */ length() { return bl
.length(); }
1807 void rgw_readv_rele(struct rgw_uio
*uio
, uint32_t flags
)
1809 RGWReadV
* rdv
= static_cast<RGWReadV
*>(uio
->uio_p1
);
1811 ::operator delete(rdv
);
1814 int rgw_readv(struct rgw_fs
*rgw_fs
,
1815 struct rgw_file_handle
*fh
, rgw_uio
*uio
, uint32_t flags
)
1818 CephContext
* cct
= static_cast<CephContext
*>(rgw_fs
->rgw
);
1819 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1820 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1822 if (! rgw_fh
->is_file())
1828 RGWGetObjRequest
req(cct
, fs
->get_user(), rgw_fh
->bucket_name(),
1829 rgw_fh
->object_name(), uio
->uio_offset
, uio
->uio_resid
,
1831 req
.do_hexdump
= false;
1833 rc
= rgwlib
.get_fe()->execute_req(&req
);
1836 RGWReadV
* rdv
= static_cast<RGWReadV
*>(
1837 ::operator new(sizeof(RGWReadV
) +
1838 (bl
.buffers().size() * sizeof(struct rgw_vio
))));
1841 RGWReadV(bl
, reinterpret_cast<rgw_vio
*>(rdv
+sizeof(RGWReadV
)));
1844 uio
->uio_cnt
= rdv
->buffers().size();
1845 uio
->uio_resid
= rdv
->length();
1846 uio
->uio_vio
= rdv
->get_vio();
1847 uio
->uio_rele
= rgw_readv_rele
;
1850 auto& buffers
= rdv
->buffers();
1851 for (auto& bp
: buffers
) {
1852 rgw_vio
*vio
= &(uio
->uio_vio
[ix
]);
1853 vio
->vio_base
= const_cast<char*>(bp
.c_str());
1854 vio
->vio_len
= bp
.length();
1855 vio
->vio_u1
= nullptr;
1856 vio
->vio_p1
= nullptr;
1868 write data to file (vector)
1870 int rgw_writev(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
1871 rgw_uio
*uio
, uint32_t flags
)
1876 CephContext
* cct
= static_cast<CephContext
*>(rgw_fs
->rgw
);
1877 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
1878 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1880 if (! rgw_fh
->is_file())
1884 for (unsigned int ix
= 0; ix
< uio
->uio_cnt
; ++ix
) {
1885 rgw_vio
*vio
= &(uio
->uio_vio
[ix
]);
1887 buffer::create_static(vio
->vio_len
,
1888 static_cast<char*>(vio
->vio_base
)));
1891 std::string oname
= rgw_fh
->relative_object_name();
1892 RGWPutObjRequest
req(cct
, fs
->get_user(), rgw_fh
->bucket_name(),
1895 int rc
= rgwlib
.get_fe()->execute_req(&req
);
1897 /* XXX update size (in request) */
1905 int rgw_fsync(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*handle
,
1911 int rgw_commit(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
1912 uint64_t offset
, uint64_t length
, uint32_t flags
)
1914 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
1916 return rgw_fh
->commit(offset
, length
, RGWFileHandle::FLAG_NONE
);