1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
4 #include "include/compat.h"
5 #include "include/rados/rgw_file.h"
11 #include "rgw_resolve.h"
15 #include "rgw_acl_s3.h"
16 #include "rgw_frontend.h"
17 #include "rgw_request.h"
18 #include "rgw_process.h"
19 #include "rgw_rest_user.h"
20 #include "rgw_rest_s3.h"
21 #include "rgw_os_lib.h"
22 #include "rgw_auth_s3.h"
24 #include "rgw_bucket.h"
27 #include "rgw_lib_frontend.h"
28 #include "rgw_perf_counters.h"
29 #include "common/errno.h"
31 #include "services/svc_zone.h"
35 #define dout_subsys ceph_subsys_rgw
43 const string
RGWFileHandle::root_name
= "/";
45 std::atomic
<uint32_t> RGWLibFS::fs_inst_counter
;
47 uint32_t RGWLibFS::write_completion_interval_s
= 10;
49 ceph::timer
<ceph::mono_clock
> RGWLibFS::write_timer
{
50 ceph::construct_suspended
};
52 inline int valid_fs_bucket_name(const string
& name
) {
53 int rc
= valid_s3_bucket_name(name
, false /* relaxed */);
55 if (name
.size() > 255)
62 inline int valid_fs_object_name(const string
& name
) {
63 int rc
= valid_s3_object_name(name
);
65 if (name
.size() > 1024)
75 std::size_t operator()(const rgw_xattrstr
& att
) const noexcept
{
76 return XXH64(att
.val
, att
.len
, 5882300);
83 bool operator()(const rgw_xattrstr
& lhs
, const rgw_xattrstr
& rhs
) const {
84 return ((lhs
.len
== rhs
.len
) &&
85 (strncmp(lhs
.val
, rhs
.val
, lhs
.len
) == 0));
89 /* well-known attributes */
90 static const std::unordered_set
<
91 rgw_xattrstr
, XattrHash
, XattrEqual
> rgw_exposed_attrs
= {
92 rgw_xattrstr
{const_cast<char*>(RGW_ATTR_ETAG
), sizeof(RGW_ATTR_ETAG
)-1}
95 static inline bool is_exposed_attr(const rgw_xattrstr
& k
) {
96 return (rgw_exposed_attrs
.find(k
) != rgw_exposed_attrs
.end());
99 LookupFHResult
RGWLibFS::stat_bucket(RGWFileHandle
* parent
, const char *path
,
100 RGWLibFS::BucketStats
& bs
,
103 LookupFHResult fhr
{nullptr, 0};
104 std::string bucket_name
{path
};
105 RGWStatBucketRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
), bucket_name
, bs
);
107 int rc
= rgwlib
.get_fe()->execute_req(&req
);
109 (req
.get_ret() == 0) &&
111 fhr
= lookup_fh(parent
, path
,
112 (flags
& RGWFileHandle::FLAG_LOCKED
)|
113 RGWFileHandle::FLAG_CREATE
|
114 RGWFileHandle::FLAG_BUCKET
);
116 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
117 if (! (flags
& RGWFileHandle::FLAG_LOCKED
)) {
120 rgw_fh
->set_times(req
.get_ctime());
121 /* restore attributes */
122 auto ux_key
= req
.get_attr(RGW_ATTR_UNIX_KEY1
);
123 auto ux_attrs
= req
.get_attr(RGW_ATTR_UNIX1
);
124 if (ux_key
&& ux_attrs
) {
125 DecodeAttrsResult dar
= rgw_fh
->decode_attrs(ux_key
, ux_attrs
);
126 if (get
<0>(dar
) || get
<1>(dar
)) {
130 if (! (flags
& RGWFileHandle::FLAG_LOCKED
)) {
131 rgw_fh
->mtx
.unlock();
138 LookupFHResult
RGWLibFS::fake_leaf(RGWFileHandle
* parent
,
140 enum rgw_fh_type type
,
141 struct stat
*st
, uint32_t st_mask
,
144 /* synthesize a minimal handle from parent, path, type, and st */
147 flags
|= RGWFileHandle::FLAG_CREATE
;
150 case RGW_FS_TYPE_DIRECTORY
:
151 flags
|= RGWFileHandle::FLAG_DIRECTORY
;
158 LookupFHResult fhr
= lookup_fh(parent
, path
, flags
);
160 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
162 lock_guard
guard(rgw_fh
->mtx
);
163 if (st_mask
& RGW_SETATTR_SIZE
) {
164 rgw_fh
->set_size(st
->st_size
);
166 if (st_mask
& RGW_SETATTR_MTIME
) {
167 rgw_fh
->set_times(st
->st_mtim
);
172 } /* RGWLibFS::fake_leaf */
174 LookupFHResult
RGWLibFS::stat_leaf(RGWFileHandle
* parent
,
176 enum rgw_fh_type type
,
179 /* find either-of <object_name>, <object_name/>, only one of
180 * which should exist; atomicity? */
183 LookupFHResult fhr
{nullptr, 0};
185 /* XXX the need for two round-trip operations to identify file or
186 * directory leaf objects is unecessary--the current proposed
187 * mechanism to avoid this is to store leaf object names with an
188 * object locator w/o trailing slash */
190 std::string obj_path
= parent
->format_child_name(path
, false);
192 for (auto ix
: { 0, 1, 2 }) {
197 if (type
== RGW_FS_TYPE_DIRECTORY
)
200 RGWStatObjRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
201 parent
->bucket_name(), obj_path
,
202 RGWStatObjRequest::FLAG_NONE
);
203 int rc
= rgwlib
.get_fe()->execute_req(&req
);
205 (req
.get_ret() == 0)) {
206 fhr
= lookup_fh(parent
, path
, RGWFileHandle::FLAG_CREATE
);
208 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
209 lock_guard
guard(rgw_fh
->mtx
);
210 rgw_fh
->set_size(req
.get_size());
211 rgw_fh
->set_times(req
.get_mtime());
212 /* restore attributes */
213 auto ux_key
= req
.get_attr(RGW_ATTR_UNIX_KEY1
);
214 auto ux_attrs
= req
.get_attr(RGW_ATTR_UNIX1
);
215 rgw_fh
->set_etag(*(req
.get_attr(RGW_ATTR_ETAG
)));
216 rgw_fh
->set_acls(*(req
.get_attr(RGW_ATTR_ACL
)));
217 if (!(flags
& RGWFileHandle::FLAG_IN_CB
) &&
218 ux_key
&& ux_attrs
) {
219 DecodeAttrsResult dar
= rgw_fh
->decode_attrs(ux_key
, ux_attrs
);
220 if (get
<0>(dar
) || get
<1>(dar
)) {
233 if (type
== RGW_FS_TYPE_FILE
)
237 RGWStatObjRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
238 parent
->bucket_name(), obj_path
,
239 RGWStatObjRequest::FLAG_NONE
);
240 int rc
= rgwlib
.get_fe()->execute_req(&req
);
242 (req
.get_ret() == 0)) {
243 fhr
= lookup_fh(parent
, path
, RGWFileHandle::FLAG_DIRECTORY
);
245 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
246 lock_guard
guard(rgw_fh
->mtx
);
247 rgw_fh
->set_size(req
.get_size());
248 rgw_fh
->set_times(req
.get_mtime());
249 /* restore attributes */
250 auto ux_key
= req
.get_attr(RGW_ATTR_UNIX_KEY1
);
251 auto ux_attrs
= req
.get_attr(RGW_ATTR_UNIX1
);
252 rgw_fh
->set_etag(*(req
.get_attr(RGW_ATTR_ETAG
)));
253 rgw_fh
->set_acls(*(req
.get_attr(RGW_ATTR_ACL
)));
254 if (!(flags
& RGWFileHandle::FLAG_IN_CB
) &&
255 ux_key
&& ux_attrs
) {
256 DecodeAttrsResult dar
= rgw_fh
->decode_attrs(ux_key
, ux_attrs
);
257 if (get
<0>(dar
) || get
<1>(dar
)) {
268 std::string object_name
{path
};
269 RGWStatLeafRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
270 parent
, object_name
);
271 int rc
= rgwlib
.get_fe()->execute_req(&req
);
273 (req
.get_ret() == 0)) {
275 /* we need rgw object's key name equal to file name, if
277 if ((flags
& RGWFileHandle::FLAG_EXACT_MATCH
) &&
278 !req
.exact_matched
) {
279 lsubdout(get_context(), rgw
, 15)
281 << ": stat leaf not exact match file name = "
285 fhr
= lookup_fh(parent
, path
,
286 RGWFileHandle::FLAG_CREATE
|
288 RGWFileHandle::FLAG_DIRECTORY
:
289 RGWFileHandle::FLAG_NONE
));
290 /* XXX we don't have an object--in general, there need not
291 * be one (just a path segment in some other object). In
292 * actual leaf an object exists, but we'd need another round
293 * trip to get attrs */
295 /* for now use the parent object's mtime */
296 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
297 lock_guard
guard(rgw_fh
->mtx
);
298 rgw_fh
->set_mtime(parent
->get_mtime());
311 } /* RGWLibFS::stat_leaf */
313 int RGWLibFS::read(RGWFileHandle
* rgw_fh
, uint64_t offset
, size_t length
,
314 size_t* bytes_read
, void* buffer
, uint32_t flags
)
316 if (! rgw_fh
->is_file())
319 if (rgw_fh
->deleted())
322 RGWReadRequest
req(get_context(), rgwlib
.get_store()->get_user(user
.user_id
),
323 rgw_fh
, offset
, length
, buffer
);
325 int rc
= rgwlib
.get_fe()->execute_req(&req
);
327 ((rc
= req
.get_ret()) == 0)) {
328 lock_guard
guard(rgw_fh
->mtx
);
329 rgw_fh
->set_atime(real_clock::to_timespec(real_clock::now()));
330 *bytes_read
= req
.nread
;
336 int RGWLibFS::readlink(RGWFileHandle
* rgw_fh
, uint64_t offset
, size_t length
,
337 size_t* bytes_read
, void* buffer
, uint32_t flags
)
339 if (! rgw_fh
->is_link())
342 if (rgw_fh
->deleted())
345 RGWReadRequest
req(get_context(), rgwlib
.get_store()->get_user(user
.user_id
),
346 rgw_fh
, offset
, length
, buffer
);
348 int rc
= rgwlib
.get_fe()->execute_req(&req
);
350 ((rc
= req
.get_ret()) == 0)) {
351 lock_guard(rgw_fh
->mtx
);
352 rgw_fh
->set_atime(real_clock::to_timespec(real_clock::now()));
353 *bytes_read
= req
.nread
;
359 int RGWLibFS::unlink(RGWFileHandle
* rgw_fh
, const char* name
, uint32_t flags
)
363 RGWFileHandle
* parent
= nullptr;
364 RGWFileHandle
* bkt_fh
= nullptr;
366 if (unlikely(flags
& RGWFileHandle::FLAG_UNLINK_THIS
)) {
368 parent
= rgw_fh
->get_parent();
372 LookupFHResult fhr
= lookup_fh(parent
, name
, RGWFileHandle::FLAG_LOCK
);
373 rgw_fh
= get
<0>(fhr
);
377 if (parent
->is_root()) {
378 /* a bucket may have an object storing Unix attributes, check
379 * for and delete it */
381 fhr
= stat_bucket(parent
, name
, bs
, (rgw_fh
) ?
382 RGWFileHandle::FLAG_LOCKED
:
383 RGWFileHandle::FLAG_NONE
);
384 bkt_fh
= get
<0>(fhr
);
385 if (unlikely(! bkt_fh
)) {
386 /* implies !rgw_fh, so also !LOCKED */
390 if (bs
.num_entries
> 1) {
391 unref(bkt_fh
); /* return stat_bucket ref */
392 if (likely(!! rgw_fh
)) { /* return lock and ref from
393 * lookup_fh (or caller in the
395 * RGWFileHandle::FLAG_UNLINK_THIS) */
396 rgw_fh
->mtx
.unlock();
401 /* delete object w/key "<bucket>/" (uxattrs), if any */
403 RGWDeleteObjRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
404 bkt_fh
->bucket_name(), oname
);
405 rc
= rgwlib
.get_fe()->execute_req(&req
);
406 /* don't care if ENOENT */
411 RGWDeleteBucketRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
), bname
);
412 rc
= rgwlib
.get_fe()->execute_req(&req
);
421 /* XXX for now, peform a hard lookup to deduce the type of
422 * object to be deleted ("foo" vs. "foo/")--also, ensures
423 * atomicity at this endpoint */
424 struct rgw_file_handle
*fh
;
425 rc
= rgw_lookup(get_fs(), parent
->get_fh(), name
, &fh
,
426 nullptr /* st */, 0 /* mask */,
427 RGW_LOOKUP_FLAG_NONE
);
432 rgw_fh
= get_rgwfh(fh
);
433 rgw_fh
->mtx
.lock(); /* LOCKED */
436 std::string oname
= rgw_fh
->relative_object_name();
437 if (rgw_fh
->is_dir()) {
438 /* for the duration of our cache timer, trust positive
440 if (rgw_fh
->has_children()) {
441 rgw_fh
->mtx
.unlock();
447 RGWDeleteObjRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
), parent
->bucket_name(),
449 rc
= rgwlib
.get_fe()->execute_req(&req
);
455 /* ENOENT when raced with other s3 gateway */
456 if (! rc
|| rc
== -ENOENT
) {
457 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
458 fh_cache
.remove(rgw_fh
->fh
.fh_hk
.object
, rgw_fh
,
459 RGWFileHandle::FHCache::FLAG_LOCK
);
463 real_time t
= real_clock::now();
464 parent
->set_mtime(real_clock::to_timespec(t
));
465 parent
->set_ctime(real_clock::to_timespec(t
));
468 rgw_fh
->mtx
.unlock();
472 } /* RGWLibFS::unlink */
474 int RGWLibFS::rename(RGWFileHandle
* src_fh
, RGWFileHandle
* dst_fh
,
475 const char *_src_name
, const char *_dst_name
)
478 /* XXX initial implementation: try-copy, and delete if copy
483 std::string src_name
{_src_name
};
484 std::string dst_name
{_dst_name
};
487 LookupFHResult fhr
= lookup_fh(src_fh
, _src_name
, RGWFileHandle::FLAG_LOCK
);
488 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
490 /* should not happen */
492 ldout(get_context(), 0) << __func__
493 << " BUG no such src renaming path="
499 /* forbid renaming of directories (unreasonable at scale) */
500 if (rgw_fh
->is_dir()) {
501 ldout(get_context(), 12) << __func__
502 << " rejecting attempt to rename directory path="
503 << rgw_fh
->full_object_name()
509 /* forbid renaming open files (violates intent, for now) */
510 if (rgw_fh
->is_open()) {
511 ldout(get_context(), 12) << __func__
512 << " rejecting attempt to rename open file path="
513 << rgw_fh
->full_object_name()
519 t
= real_clock::now();
521 for (int ix
: {0, 1}) {
525 RGWCopyObjRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
526 src_fh
, dst_fh
, src_name
, dst_name
);
527 int rc
= rgwlib
.get_fe()->execute_req(&req
);
529 ((rc
= req
.get_ret()) != 0)) {
530 ldout(get_context(), 1)
532 << " rename step 0 failed src="
533 << src_fh
->full_object_name() << " " << src_name
534 << " dst=" << dst_fh
->full_object_name()
540 ldout(get_context(), 12)
542 << " rename step 0 success src="
543 << src_fh
->full_object_name() << " " << src_name
544 << " dst=" << dst_fh
->full_object_name()
548 /* update dst change id */
549 dst_fh
->set_times(t
);
554 rc
= this->unlink(rgw_fh
/* LOCKED */, _src_name
,
555 RGWFileHandle::FLAG_UNLINK_THIS
);
558 ldout(get_context(), 12)
560 << " rename step 1 success src="
561 << src_fh
->full_object_name() << " " << src_name
562 << " dst=" << dst_fh
->full_object_name()
566 /* update src change id */
567 src_fh
->set_times(t
);
569 ldout(get_context(), 1)
571 << " rename step 1 failed src="
572 << src_fh
->full_object_name() << " " << src_name
573 << " dst=" << dst_fh
->full_object_name()
585 rgw_fh
->mtx
.unlock(); /* !LOCKED */
586 unref(rgw_fh
); /* -ref */
590 } /* RGWLibFS::rename */
592 MkObjResult
RGWLibFS::mkdir(RGWFileHandle
* parent
, const char *name
,
593 struct stat
*st
, uint32_t mask
, uint32_t flags
)
596 rgw_file_handle
*lfh
;
598 rc
= rgw_lookup(get_fs(), parent
->get_fh(), name
, &lfh
,
599 nullptr /* st */, 0 /* mask */,
600 RGW_LOOKUP_FLAG_NONE
);
603 rc
= rgw_fh_rele(get_fs(), lfh
, RGW_FH_RELE_FLAG_NONE
);
604 // ignore return code
605 return MkObjResult
{nullptr, -EEXIST
};
608 MkObjResult mkr
{nullptr, -EINVAL
};
610 RGWFileHandle
* rgw_fh
= nullptr;
611 buffer::list ux_key
, ux_attrs
;
613 fhr
= lookup_fh(parent
, name
,
614 RGWFileHandle::FLAG_CREATE
|
615 RGWFileHandle::FLAG_DIRECTORY
|
616 RGWFileHandle::FLAG_LOCK
);
617 rgw_fh
= get
<0>(fhr
);
619 rgw_fh
->create_stat(st
, mask
);
620 rgw_fh
->set_times(real_clock::now());
622 rgw_fh
->encode_attrs(ux_key
, ux_attrs
);
624 rgw_fh
->stat(st
, RGWFileHandle::FLAG_LOCKED
);
625 get
<0>(mkr
) = rgw_fh
;
631 if (parent
->is_root()) {
634 /* enforce S3 name restrictions */
635 rc
= valid_fs_bucket_name(bname
);
637 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
638 fh_cache
.remove(rgw_fh
->fh
.fh_hk
.object
, rgw_fh
,
639 RGWFileHandle::FHCache::FLAG_LOCK
);
640 rgw_fh
->mtx
.unlock();
642 get
<0>(mkr
) = nullptr;
647 RGWCreateBucketRequest
req(get_context(),
648 rgwlib
.get_store()->get_user(user
.user_id
), bname
);
651 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
652 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
654 rc
= rgwlib
.get_fe()->execute_req(&req
);
657 /* create an object representing the directory */
659 string dir_name
= parent
->format_child_name(name
, true);
661 /* need valid S3 name (characters, length <= 1024, etc) */
662 rc
= valid_fs_object_name(dir_name
);
664 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
665 fh_cache
.remove(rgw_fh
->fh
.fh_hk
.object
, rgw_fh
,
666 RGWFileHandle::FHCache::FLAG_LOCK
);
667 rgw_fh
->mtx
.unlock();
669 get
<0>(mkr
) = nullptr;
674 RGWPutObjRequest
req(get_context(), rgwlib
.get_store()->get_user(user
.user_id
),
675 parent
->bucket_name(), dir_name
, bl
);
678 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
679 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
681 rc
= rgwlib
.get_fe()->execute_req(&req
);
688 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
689 rgw_fh
->mtx
.unlock(); /* !LOCKED */
691 get
<0>(mkr
) = nullptr;
696 real_time t
= real_clock::now();
697 parent
->set_mtime(real_clock::to_timespec(t
));
698 parent
->set_ctime(real_clock::to_timespec(t
));
699 rgw_fh
->mtx
.unlock(); /* !LOCKED */
705 } /* RGWLibFS::mkdir */
707 MkObjResult
RGWLibFS::create(RGWFileHandle
* parent
, const char *name
,
708 struct stat
*st
, uint32_t mask
, uint32_t flags
)
714 rgw_file_handle
*lfh
;
715 rc
= rgw_lookup(get_fs(), parent
->get_fh(), name
, &lfh
,
716 nullptr /* st */, 0 /* mask */,
717 RGW_LOOKUP_FLAG_NONE
);
720 rc
= rgw_fh_rele(get_fs(), lfh
, RGW_FH_RELE_FLAG_NONE
);
721 // ignore return code
722 return MkObjResult
{nullptr, -EEXIST
};
725 /* expand and check name */
726 std::string obj_name
= parent
->format_child_name(name
, false);
727 rc
= valid_fs_object_name(obj_name
);
729 return MkObjResult
{nullptr, rc
};
734 RGWPutObjRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
735 parent
->bucket_name(), obj_name
, bl
);
736 MkObjResult mkr
{nullptr, -EINVAL
};
738 rc
= rgwlib
.get_fe()->execute_req(&req
);
744 LookupFHResult fhr
= lookup_fh(parent
, name
, RGWFileHandle::FLAG_CREATE
|
745 RGWFileHandle::FLAG_LOCK
);
746 RGWFileHandle
* rgw_fh
= get
<0>(fhr
);
748 if (get
<1>(fhr
) & RGWFileHandle::FLAG_CREATE
) {
749 /* fill in stat data */
750 real_time t
= real_clock::now();
751 rgw_fh
->create_stat(st
, mask
);
752 rgw_fh
->set_times(t
);
754 parent
->set_mtime(real_clock::to_timespec(t
));
755 parent
->set_ctime(real_clock::to_timespec(t
));
758 (void) rgw_fh
->stat(st
, RGWFileHandle::FLAG_LOCKED
);
760 rgw_fh
->set_etag(*(req
.get_attr(RGW_ATTR_ETAG
)));
761 rgw_fh
->set_acls(*(req
.get_attr(RGW_ATTR_ACL
)));
763 get
<0>(mkr
) = rgw_fh
;
764 rgw_fh
->mtx
.unlock();
771 /* case like : quota exceed will be considered as fail too*/
776 } /* RGWLibFS::create */
778 MkObjResult
RGWLibFS::symlink(RGWFileHandle
* parent
, const char *name
,
779 const char* link_path
, struct stat
*st
, uint32_t mask
, uint32_t flags
)
785 rgw_file_handle
*lfh
;
786 rc
= rgw_lookup(get_fs(), parent
->get_fh(), name
, &lfh
,
787 nullptr /* st */, 0 /* mask */,
788 RGW_LOOKUP_FLAG_NONE
);
791 rc
= rgw_fh_rele(get_fs(), lfh
, RGW_FH_RELE_FLAG_NONE
);
792 // ignore return code
793 return MkObjResult
{nullptr, -EEXIST
};
796 MkObjResult mkr
{nullptr, -EINVAL
};
798 RGWFileHandle
* rgw_fh
= nullptr;
799 buffer::list ux_key
, ux_attrs
;
801 fhr
= lookup_fh(parent
, name
,
802 RGWFileHandle::FLAG_CREATE
|
803 RGWFileHandle::FLAG_SYMBOLIC_LINK
|
804 RGWFileHandle::FLAG_LOCK
);
805 rgw_fh
= get
<0>(fhr
);
807 rgw_fh
->create_stat(st
, mask
);
808 rgw_fh
->set_times(real_clock::now());
810 rgw_fh
->encode_attrs(ux_key
, ux_attrs
);
813 get
<0>(mkr
) = rgw_fh
;
819 /* need valid S3 name (characters, length <= 1024, etc) */
820 rc
= valid_fs_object_name(name
);
822 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
823 fh_cache
.remove(rgw_fh
->fh
.fh_hk
.object
, rgw_fh
,
824 RGWFileHandle::FHCache::FLAG_LOCK
);
825 rgw_fh
->mtx
.unlock();
827 get
<0>(mkr
) = nullptr;
832 string obj_name
= std::string(name
);
833 /* create an object representing the directory */
839 buffer::create_static(len
, static_cast<char*>(buffer
)));
843 buffer::copy(link_path
, strlen(link_path
)));
846 RGWPutObjRequest
req(get_context(), rgwlib
.get_store()->get_user(user
.user_id
),
847 parent
->bucket_name(), obj_name
, bl
);
850 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
851 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
853 rc
= rgwlib
.get_fe()->execute_req(&req
);
858 rgw_fh
->flags
|= RGWFileHandle::FLAG_DELETED
;
859 rgw_fh
->mtx
.unlock(); /* !LOCKED */
861 get
<0>(mkr
) = nullptr;
866 real_time t
= real_clock::now();
867 parent
->set_mtime(real_clock::to_timespec(t
));
868 parent
->set_ctime(real_clock::to_timespec(t
));
869 rgw_fh
->mtx
.unlock(); /* !LOCKED */
875 } /* RGWLibFS::symlink */
877 int RGWLibFS::getattr(RGWFileHandle
* rgw_fh
, struct stat
* st
)
879 switch(rgw_fh
->fh
.fh_type
) {
880 case RGW_FS_TYPE_FILE
:
882 if (rgw_fh
->deleted())
889 /* if rgw_fh is a directory, mtime will be advanced */
890 return rgw_fh
->stat(st
);
891 } /* RGWLibFS::getattr */
893 int RGWLibFS::setattr(RGWFileHandle
* rgw_fh
, struct stat
* st
, uint32_t mask
,
897 buffer::list ux_key
, ux_attrs
;
898 buffer::list etag
= rgw_fh
->get_etag();
899 buffer::list acls
= rgw_fh
->get_acls();
901 lock_guard
guard(rgw_fh
->mtx
);
903 switch(rgw_fh
->fh
.fh_type
) {
904 case RGW_FS_TYPE_FILE
:
906 if (rgw_fh
->deleted())
914 string obj_name
{rgw_fh
->relative_object_name()};
916 if (rgw_fh
->is_dir() &&
917 (likely(! rgw_fh
->is_bucket()))) {
921 RGWSetAttrsRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
922 rgw_fh
->bucket_name(), obj_name
);
924 rgw_fh
->create_stat(st
, mask
);
925 rgw_fh
->encode_attrs(ux_key
, ux_attrs
);
928 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
929 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
930 req
.emplace_attr(RGW_ATTR_ETAG
, std::move(etag
));
931 req
.emplace_attr(RGW_ATTR_ACL
, std::move(acls
));
933 rc
= rgwlib
.get_fe()->execute_req(&req
);
937 /* special case: materialize placeholder dir */
939 RGWPutObjRequest
req(get_context(), rgwlib
.get_store()->get_user(user
.user_id
), rgw_fh
->bucket_name(),
942 rgw_fh
->encode_attrs(ux_key
, ux_attrs
); /* because std::moved */
945 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
946 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
948 rc
= rgwlib
.get_fe()->execute_req(&req
);
952 if ((rc
!= 0) || (rc2
!= 0)) {
956 rgw_fh
->set_ctime(real_clock::to_timespec(real_clock::now()));
959 } /* RGWLibFS::setattr */
961 static inline std::string
prefix_xattr_keystr(const rgw_xattrstr
& key
) {
963 keystr
.reserve(sizeof(RGW_ATTR_META_PREFIX
) + key
.len
);
964 keystr
+= string
{RGW_ATTR_META_PREFIX
};
965 keystr
+= string
{key
.val
, key
.len
};
969 static inline std::string_view
unprefix_xattr_keystr(const std::string
& key
)
971 std::string_view svk
{key
};
972 auto pos
= svk
.find(RGW_ATTR_META_PREFIX
);
973 if (pos
== std::string_view::npos
) {
974 return std::string_view
{""};
975 } else if (pos
== 0) {
976 svk
.remove_prefix(sizeof(RGW_ATTR_META_PREFIX
)-1);
981 int RGWLibFS::getxattrs(RGWFileHandle
* rgw_fh
, rgw_xattrlist
*attrs
,
982 rgw_getxattr_cb cb
, void *cb_arg
,
985 /* cannot store on fs_root, should not on buckets? */
986 if ((rgw_fh
->is_bucket()) ||
987 (rgw_fh
->is_root())) {
992 string obj_name
{rgw_fh
->relative_object_name2()};
994 RGWGetAttrsRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
995 rgw_fh
->bucket_name(), obj_name
);
997 for (uint32_t ix
= 0; ix
< attrs
->xattr_cnt
; ++ix
) {
998 auto& xattr
= attrs
->xattrs
[ix
];
1000 /* pass exposed attr keys as given, else prefix */
1001 std::string k
= is_exposed_attr(xattr
.key
)
1002 ? std::string
{xattr
.key
.val
, xattr
.key
.len
}
1003 : prefix_xattr_keystr(xattr
.key
);
1005 req
.emplace_key(std::move(k
));
1008 if (ldlog_p1(get_context(), ceph_subsys_rgw
, 15)) {
1009 lsubdout(get_context(), rgw
, 15)
1011 << " get keys for: "
1012 << rgw_fh
->object_name()
1015 for (const auto& attr
: req
.get_attrs()) {
1016 lsubdout(get_context(), rgw
, 15)
1017 << "\tkey: " << attr
.first
<< dendl
;
1021 rc
= rgwlib
.get_fe()->execute_req(&req
);
1022 rc2
= req
.get_ret();
1023 rc3
= ((rc
== 0) && (rc2
== 0)) ? 0 : -EIO
;
1025 /* call back w/xattr data */
1027 const auto& attrs
= req
.get_attrs();
1028 for (const auto& attr
: attrs
) {
1030 if (!attr
.second
.has_value())
1033 const auto& k
= attr
.first
;
1034 const auto& v
= attr
.second
.value();
1036 /* return exposed attr keys as given, else unprefix --
1037 * yes, we could have memoized the exposed check, but
1038 * to be efficient it would need to be saved with
1039 * RGWGetAttrs::attrs, I think */
1040 std::string_view svk
=
1041 is_exposed_attr(rgw_xattrstr
{const_cast<char*>(k
.c_str()),
1042 uint32_t(k
.length())})
1044 : unprefix_xattr_keystr(k
);
1046 /* skip entries not matching prefix */
1050 rgw_xattrstr xattr_k
= { const_cast<char*>(svk
.data()),
1051 uint32_t(svk
.length())};
1052 rgw_xattrstr xattr_v
=
1053 {const_cast<char*>(const_cast<buffer::list
&>(v
).c_str()),
1054 uint32_t(v
.length())};
1055 rgw_xattr xattr
= { xattr_k
, xattr_v
};
1056 rgw_xattrlist xattrlist
= { &xattr
, 1 };
1058 cb(&xattrlist
, cb_arg
, RGW_GETXATTR_FLAG_NONE
);
1063 } /* RGWLibFS::getxattrs */
1065 int RGWLibFS::lsxattrs(
1066 RGWFileHandle
* rgw_fh
, rgw_xattrstr
*filter_prefix
, rgw_getxattr_cb cb
,
1067 void *cb_arg
, uint32_t flags
)
1069 /* cannot store on fs_root, should not on buckets? */
1070 if ((rgw_fh
->is_bucket()) ||
1071 (rgw_fh
->is_root())) {
1076 string obj_name
{rgw_fh
->relative_object_name2()};
1078 RGWGetAttrsRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
1079 rgw_fh
->bucket_name(), obj_name
);
1081 rc
= rgwlib
.get_fe()->execute_req(&req
);
1082 rc2
= req
.get_ret();
1083 rc3
= ((rc
== 0) && (rc2
== 0)) ? 0 : -EIO
;
1085 /* call back w/xattr data--check for eof */
1087 const auto& keys
= req
.get_attrs();
1088 for (const auto& k
: keys
) {
1090 /* return exposed attr keys as given, else unprefix */
1091 std::string_view svk
=
1092 is_exposed_attr(rgw_xattrstr
{const_cast<char*>(k
.first
.c_str()),
1093 uint32_t(k
.first
.length())})
1095 : unprefix_xattr_keystr(k
.first
);
1097 /* skip entries not matching prefix */
1101 rgw_xattrstr xattr_k
= { const_cast<char*>(svk
.data()),
1102 uint32_t(svk
.length())};
1103 rgw_xattrstr xattr_v
= { nullptr, 0 };
1104 rgw_xattr xattr
= { xattr_k
, xattr_v
};
1105 rgw_xattrlist xattrlist
= { &xattr
, 1 };
1107 auto cbr
= cb(&xattrlist
, cb_arg
, RGW_LSXATTR_FLAG_NONE
);
1108 if (cbr
& RGW_LSXATTR_FLAG_STOP
)
1114 } /* RGWLibFS::lsxattrs */
1116 int RGWLibFS::setxattrs(RGWFileHandle
* rgw_fh
, rgw_xattrlist
*attrs
,
1119 /* cannot store on fs_root, should not on buckets? */
1120 if ((rgw_fh
->is_bucket()) ||
1121 (rgw_fh
->is_root())) {
1126 string obj_name
{rgw_fh
->relative_object_name2()};
1128 RGWSetAttrsRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
1129 rgw_fh
->bucket_name(), obj_name
);
1131 for (uint32_t ix
= 0; ix
< attrs
->xattr_cnt
; ++ix
) {
1132 auto& xattr
= attrs
->xattrs
[ix
];
1133 buffer::list attr_bl
;
1134 /* don't allow storing at RGW_ATTR_META_PREFIX */
1135 if (! (xattr
.key
.len
> 0))
1138 /* reject lexical match with any exposed attr */
1139 if (is_exposed_attr(xattr
.key
))
1142 string k
= prefix_xattr_keystr(xattr
.key
);
1143 attr_bl
.append(xattr
.val
.val
, xattr
.val
.len
);
1144 req
.emplace_attr(k
.c_str(), std::move(attr_bl
));
1147 /* don't send null requests */
1148 if (! (req
.get_attrs().size() > 0)) {
1152 rc
= rgwlib
.get_fe()->execute_req(&req
);
1153 rc2
= req
.get_ret();
1155 return (((rc
== 0) && (rc2
== 0)) ? 0 : -EIO
);
1157 } /* RGWLibFS::setxattrs */
1159 int RGWLibFS::rmxattrs(RGWFileHandle
* rgw_fh
, rgw_xattrlist
* attrs
,
1162 /* cannot store on fs_root, should not on buckets? */
1163 if ((rgw_fh
->is_bucket()) ||
1164 (rgw_fh
->is_root())) {
1169 string obj_name
{rgw_fh
->relative_object_name2()};
1171 RGWRMAttrsRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
1172 rgw_fh
->bucket_name(), obj_name
);
1174 for (uint32_t ix
= 0; ix
< attrs
->xattr_cnt
; ++ix
) {
1175 auto& xattr
= attrs
->xattrs
[ix
];
1176 /* don't allow storing at RGW_ATTR_META_PREFIX */
1177 if (! (xattr
.key
.len
> 0)) {
1180 string k
= prefix_xattr_keystr(xattr
.key
);
1181 req
.emplace_key(std::move(k
));
1184 /* don't send null requests */
1185 if (! (req
.get_attrs().size() > 0)) {
1189 rc
= rgwlib
.get_fe()->execute_req(&req
);
1190 rc2
= req
.get_ret();
1192 return (((rc
== 0) && (rc2
== 0)) ? 0 : -EIO
);
1194 } /* RGWLibFS::rmxattrs */
1196 /* called with rgw_fh->mtx held */
1197 void RGWLibFS::update_fh(RGWFileHandle
*rgw_fh
)
1200 string obj_name
{rgw_fh
->relative_object_name()};
1201 buffer::list ux_key
, ux_attrs
;
1203 if (rgw_fh
->is_dir() &&
1204 (likely(! rgw_fh
->is_bucket()))) {
1208 lsubdout(get_context(), rgw
, 17)
1210 << " update old versioned fh : " << obj_name
1213 RGWSetAttrsRequest
req(cct
, rgwlib
.get_store()->get_user(user
.user_id
),
1214 rgw_fh
->bucket_name(), obj_name
);
1216 rgw_fh
->encode_attrs(ux_key
, ux_attrs
);
1218 req
.emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
1219 req
.emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
1221 rc
= rgwlib
.get_fe()->execute_req(&req
);
1222 rc2
= req
.get_ret();
1224 if ((rc
!= 0) || (rc2
!= 0)) {
1225 lsubdout(get_context(), rgw
, 17)
1227 << " update fh failed : " << obj_name
1230 } /* RGWLibFS::update_fh */
1232 void RGWLibFS::close()
1234 state
.flags
|= FLAG_CLOSED
;
1240 explicit ObjUnref(RGWLibFS
* _fs
) : fs(_fs
) {}
1241 void operator()(RGWFileHandle
* fh
) const {
1242 lsubdout(fs
->get_context(), rgw
, 5)
1243 << __PRETTY_FUNCTION__
1245 << " before ObjUnref refs=" << fh
->get_refcnt()
1251 /* force cache drain, forces objects to evict */
1252 fh_cache
.drain(ObjUnref(this),
1253 RGWFileHandle::FHCache::FLAG_LOCK
);
1254 rgwlib
.get_fe()->get_process()->unregister_fs(this);
1256 } /* RGWLibFS::close */
1258 inline std::ostream
& operator<<(std::ostream
&os
, fh_key
const &fhk
) {
1259 os
<< "<fh_key: bucket=";
1260 os
<< fhk
.fh_hk
.bucket
;
1262 os
<< fhk
.fh_hk
.object
;
1267 inline std::ostream
& operator<<(std::ostream
&os
, struct timespec
const &ts
) {
1268 os
<< "<timespec: tv_sec=";
1276 std::ostream
& operator<<(std::ostream
&os
, RGWLibFS::event
const &ev
) {
1279 case RGWLibFS::event::type::READDIR
:
1280 os
<< "type=READDIR;";
1283 os
<< "type=UNKNOWN;";
1286 os
<< "fid=" << ev
.fhk
.fh_hk
.bucket
<< ":" << ev
.fhk
.fh_hk
.object
1287 << ";ts=" << ev
.ts
<< ">";
1294 using directory
= RGWFileHandle::directory
;
1296 /* dirent invalidate timeout--basically, the upper-bound on
1297 * inconsistency with the S3 namespace */
1299 = get_context()->_conf
->rgw_nfs_namespace_expire_secs
;
1301 /* max events to gc in one cycle */
1302 uint32_t max_ev
= get_context()->_conf
->rgw_nfs_max_gc
;
1304 struct timespec now
, expire_ts
;
1307 std::deque
<event
> &events
= state
.events
;
1310 (void) clock_gettime(CLOCK_MONOTONIC_COARSE
, &now
);
1311 lsubdout(get_context(), rgw
, 15)
1312 << "GC: top of expire loop"
1314 << " expire_s=" << expire_s
1317 lock_guard
guard(state
.mtx
); /* LOCKED */
1318 lsubdout(get_context(), rgw
, 15)
1320 << " count=" << events
.size()
1323 /* just return if no events */
1324 if (events
.empty()) {
1328 (events
.size() < 500) ? max_ev
: (events
.size() / 4);
1329 for (uint32_t ix
= 0; (ix
< _max_ev
) && (events
.size() > 0); ++ix
) {
1330 event
& ev
= events
.front();
1332 expire_ts
.tv_sec
+= expire_s
;
1333 if (expire_ts
> now
) {
1342 for (auto& ev
: ve
) {
1343 lsubdout(get_context(), rgw
, 15)
1344 << "try-expire ev: " << ev
<< dendl
;
1345 if (likely(ev
.t
== event::type::READDIR
)) {
1346 RGWFileHandle
* rgw_fh
= lookup_handle(ev
.fhk
.fh_hk
);
1347 lsubdout(get_context(), rgw
, 15)
1348 << "ev rgw_fh: " << rgw_fh
<< dendl
;
1350 RGWFileHandle::directory
* d
;
1351 if (unlikely(! rgw_fh
->is_dir())) {
1352 lsubdout(get_context(), rgw
, 0)
1354 << " BUG non-directory found with READDIR event "
1355 << "(" << rgw_fh
->bucket_name() << ","
1356 << rgw_fh
->object_name() << ")"
1360 /* maybe clear state */
1361 d
= get
<directory
>(&rgw_fh
->variant_type
);
1363 struct timespec ev_ts
= ev
.ts
;
1364 lock_guard
guard(rgw_fh
->mtx
);
1365 struct timespec d_last_readdir
= d
->last_readdir
;
1366 if (unlikely(ev_ts
< d_last_readdir
)) {
1367 /* readdir cycle in progress, don't invalidate */
1368 lsubdout(get_context(), rgw
, 15)
1369 << "GC: delay expiration for "
1370 << rgw_fh
->object_name()
1371 << " ev.ts=" << ev_ts
1372 << " last_readdir=" << d_last_readdir
1376 lsubdout(get_context(), rgw
, 15)
1378 << rgw_fh
->object_name()
1380 rgw_fh
->clear_state();
1381 rgw_fh
->invalidate();
1387 } /* event::type::READDIR */
1390 } while (! (stop
|| shutdown
));
1391 } /* RGWLibFS::gc */
1393 std::ostream
& operator<<(std::ostream
&os
,
1394 RGWFileHandle
const &rgw_fh
)
1396 const auto& fhk
= rgw_fh
.get_key();
1397 const auto& fh
= const_cast<RGWFileHandle
&>(rgw_fh
).get_fh();
1398 os
<< "<RGWFileHandle:";
1399 os
<< "addr=" << &rgw_fh
<< ";";
1400 switch (fh
->fh_type
) {
1401 case RGW_FS_TYPE_DIRECTORY
:
1402 os
<< "type=DIRECTORY;";
1404 case RGW_FS_TYPE_FILE
:
1408 os
<< "type=UNKNOWN;";
1411 os
<< "fid=" << fhk
.fh_hk
.bucket
<< ":" << fhk
.fh_hk
.object
<< ";";
1412 os
<< "name=" << rgw_fh
.object_name() << ";";
1413 os
<< "refcnt=" << rgw_fh
.get_refcnt() << ";";
1418 RGWFileHandle::~RGWFileHandle() {
1419 /* !recycle case, handle may STILL be in handle table, BUT
1420 * the partition lock is not held in this path */
1421 if (fh_hook
.is_linked()) {
1422 fs
->fh_cache
.remove(fh
.fh_hk
.object
, this, FHCache::FLAG_LOCK
);
1424 /* cond-unref parent */
1425 if (parent
&& (! parent
->is_mount())) {
1426 /* safe because if parent->unref causes its deletion,
1427 * there are a) by refcnt, no other objects/paths pointing
1428 * to it and b) by the semantics of valid iteration of
1429 * fh_lru (observed, e.g., by cohort_lru<T,...>::drain())
1430 * no unsafe iterators reaching it either--n.b., this constraint
1431 * is binding oncode which may in future attempt to e.g.,
1432 * cause the eviction of objects in LRU order */
1433 (void) get_fs()->unref(parent
);
1437 fh_key
RGWFileHandle::make_fhk(const std::string
& name
)
1439 std::string tenant
= get_fs()->get_user()->user_id
.to_str();
1441 /* S3 bucket -- assert mount-at-bucket case reaches here */
1442 return fh_key(name
, name
, tenant
);
1444 std::string key_name
= make_key_name(name
.c_str());
1445 return fh_key(fhk
.fh_hk
.bucket
, key_name
.c_str(), tenant
);
1449 void RGWFileHandle::encode_attrs(ceph::buffer::list
& ux_key1
,
1450 ceph::buffer::list
& ux_attrs1
)
1453 fh_key
fhk(this->fh
.fh_hk
);
1454 encode(fhk
, ux_key1
);
1455 encode(*this, ux_attrs1
);
1456 } /* RGWFileHandle::encode_attrs */
1458 DecodeAttrsResult
RGWFileHandle::decode_attrs(const ceph::buffer::list
* ux_key1
,
1459 const ceph::buffer::list
* ux_attrs1
)
1462 DecodeAttrsResult dar
{ false, false };
1464 auto bl_iter_key1
= ux_key1
->cbegin();
1465 decode(fhk
, bl_iter_key1
);
1468 auto bl_iter_unix1
= ux_attrs1
->cbegin();
1469 decode(*this, bl_iter_unix1
);
1470 if (this->state
.version
< 2) {
1475 } /* RGWFileHandle::decode_attrs */
1477 bool RGWFileHandle::reclaim(const cohort::lru::ObjectFactory
* newobj_fac
) {
1478 lsubdout(fs
->get_context(), rgw
, 17)
1479 << __func__
<< " " << *this
1481 auto factory
= dynamic_cast<const RGWFileHandle::Factory
*>(newobj_fac
);
1482 if (factory
== nullptr) {
1485 /* make sure the reclaiming object is the same partiton with newobject factory,
1486 * then we can recycle the object, and replace with newobject */
1487 if (!fs
->fh_cache
.is_same_partition(factory
->fhk
.fh_hk
.object
, fh
.fh_hk
.object
)) {
1490 /* in the non-delete case, handle may still be in handle table */
1491 if (fh_hook
.is_linked()) {
1492 /* in this case, we are being called from a context which holds
1493 * the partition lock */
1494 fs
->fh_cache
.remove(fh
.fh_hk
.object
, this, FHCache::FLAG_NONE
);
1497 } /* RGWFileHandle::reclaim */
1499 bool RGWFileHandle::has_children() const
1501 if (unlikely(! is_dir()))
1504 RGWRMdirCheck
req(fs
->get_context(),
1505 rgwlib
.get_store()->get_user(fs
->get_user()->user_id
),
1507 int rc
= rgwlib
.get_fe()->execute_req(&req
);
1509 return req
.valid
&& req
.has_children
;
1515 std::ostream
& operator<<(std::ostream
&os
,
1516 RGWFileHandle::readdir_offset
const &offset
)
1519 if (unlikely(!! get
<uint64_t*>(&offset
))) {
1520 uint64_t* ioff
= get
<uint64_t*>(offset
);
1524 os
<< get
<const char*>(offset
);
1528 int RGWFileHandle::readdir(rgw_readdir_cb rcb
, void *cb_arg
,
1529 readdir_offset offset
,
1530 bool *eof
, uint32_t flags
)
1532 using event
= RGWLibFS::event
;
1535 struct timespec now
;
1536 CephContext
* cct
= fs
->get_context();
1538 lsubdout(cct
, rgw
, 10)
1539 << __func__
<< " readdir called on "
1543 directory
* d
= get
<directory
>(&variant_type
);
1545 (void) clock_gettime(CLOCK_MONOTONIC_COARSE
, &now
); /* !LOCKED */
1546 lock_guard
guard(mtx
);
1547 d
->last_readdir
= now
;
1553 if (likely(!! get
<const char*>(&offset
))) {
1554 mk
= const_cast<char*>(get
<const char*>(offset
));
1557 initial_off
= (*get
<uint64_t*>(offset
) == 0);
1561 RGWListBucketsRequest
req(cct
, rgwlib
.get_store()->get_user(fs
->get_user()->user_id
),
1562 this, rcb
, cb_arg
, offset
);
1563 rc
= rgwlib
.get_fe()->execute_req(&req
);
1565 (void) clock_gettime(CLOCK_MONOTONIC_COARSE
, &now
); /* !LOCKED */
1566 lock_guard
guard(mtx
);
1570 inc_nlink(req
.d_count
);
1574 RGWReaddirRequest
req(cct
, rgwlib
.get_store()->get_user(fs
->get_user()->user_id
),
1575 this, rcb
, cb_arg
, offset
);
1576 rc
= rgwlib
.get_fe()->execute_req(&req
);
1578 (void) clock_gettime(CLOCK_MONOTONIC_COARSE
, &now
); /* !LOCKED */
1579 lock_guard
guard(mtx
);
1583 inc_nlink(req
.d_count
);
1588 event
ev(event::type::READDIR
, get_key(), state
.atime
);
1589 lock_guard
sguard(fs
->state
.mtx
);
1590 fs
->state
.push_event(ev
);
1592 lsubdout(fs
->get_context(), rgw
, 15)
1594 << " final link count=" << state
.nlink
1598 } /* RGWFileHandle::readdir */
1600 int RGWFileHandle::write(uint64_t off
, size_t len
, size_t *bytes_written
,
1604 using WriteCompletion
= RGWLibFS::WriteCompletion
;
1606 lock_guard
guard(mtx
);
1610 file
* f
= get
<file
>(&variant_type
);
1615 lsubdout(fs
->get_context(), rgw
, 5)
1617 << " write attempted on deleted object "
1618 << this->object_name()
1620 /* zap write transaction, if any */
1622 delete f
->write_req
;
1623 f
->write_req
= nullptr;
1628 if (! f
->write_req
) {
1629 /* guard--we do not support (e.g., COW-backed) partial writes */
1631 lsubdout(fs
->get_context(), rgw
, 5)
1633 << " " << object_name()
1634 << " non-0 initial write position " << off
1635 << " (mounting with -o sync required)"
1641 std::string object_name
= relative_object_name();
1643 new RGWWriteRequest(rgwlib
.get_store(),
1644 rgwlib
.get_store()->get_user(fs
->get_user()->user_id
),
1645 this, bucket_name(), object_name
);
1646 rc
= rgwlib
.get_fe()->start_req(f
->write_req
);
1648 lsubdout(fs
->get_context(), rgw
, 5)
1650 << this->object_name()
1651 << " write start failed " << off
1652 << " (" << rc
<< ")"
1654 /* zap failed write transaction */
1655 delete f
->write_req
;
1656 f
->write_req
= nullptr;
1659 if (stateless_open()) {
1660 /* start write timer */
1661 f
->write_req
->timer_id
=
1662 RGWLibFS::write_timer
.add_event(
1663 std::chrono::seconds(RGWLibFS::write_completion_interval_s
),
1664 WriteCompletion(*this));
1670 if ((static_cast<off_t
>(off
) < f
->write_req
->real_ofs
) &&
1671 ((f
->write_req
->real_ofs
- off
) <= len
)) {
1672 overlap
= f
->write_req
->real_ofs
- off
;
1673 off
= f
->write_req
->real_ofs
;
1674 buffer
= static_cast<char*>(buffer
) + overlap
;
1682 buffer::create_static(len
, static_cast<char*>(buffer
)));
1685 buffer::copy(static_cast<char*>(buffer
), len
));
1688 f
->write_req
->put_data(off
, bl
);
1689 rc
= f
->write_req
->exec_continue();
1692 size_t min_size
= off
+ len
;
1693 if (min_size
> get_size())
1695 if (stateless_open()) {
1696 /* bump write timer */
1697 RGWLibFS::write_timer
.adjust_event(
1698 f
->write_req
->timer_id
, std::chrono::seconds(10));
1701 /* continuation failed (e.g., non-contiguous write position) */
1702 lsubdout(fs
->get_context(), rgw
, 5)
1705 << " failed write at position " << off
1706 << " (fails write transaction) "
1708 /* zap failed write transaction */
1709 delete f
->write_req
;
1710 f
->write_req
= nullptr;
1714 *bytes_written
= (rc
== 0) ? (len
+ overlap
) : 0;
1716 } /* RGWFileHandle::write */
1718 int RGWFileHandle::write_finish(uint32_t flags
)
1720 unique_lock guard
{mtx
, std::defer_lock
};
1723 if (! (flags
& FLAG_LOCKED
)) {
1727 file
* f
= get
<file
>(&variant_type
);
1728 if (f
&& (f
->write_req
)) {
1729 lsubdout(fs
->get_context(), rgw
, 10)
1731 << " finishing write trans on " << object_name()
1733 rc
= rgwlib
.get_fe()->finish_req(f
->write_req
);
1735 rc
= f
->write_req
->get_ret();
1737 delete f
->write_req
;
1738 f
->write_req
= nullptr;
1742 } /* RGWFileHandle::write_finish */
1744 int RGWFileHandle::close()
1746 lock_guard
guard(mtx
);
1748 int rc
= write_finish(FLAG_LOCKED
);
1750 flags
&= ~FLAG_OPEN
;
1751 flags
&= ~FLAG_STATELESS_OPEN
;
1754 } /* RGWFileHandle::close */
1756 RGWFileHandle::file::~file()
1761 void RGWFileHandle::clear_state()
1763 directory
* d
= get
<directory
>(&variant_type
);
1766 d
->last_marker
= rgw_obj_key
{};
1770 void RGWFileHandle::advance_mtime(uint32_t flags
) {
1771 /* intended for use on directories, fast-forward mtime so as to
1772 * ensure a new, higher value for the change attribute */
1773 unique_lock
uniq(mtx
, std::defer_lock
);
1774 if (likely(! (flags
& RGWFileHandle::FLAG_LOCKED
))) {
1778 /* advance mtime only if stored mtime is older than the
1779 * configured namespace expiration */
1780 auto now
= real_clock::now();
1781 auto cmptime
= state
.mtime
;
1783 fs
->get_context()->_conf
->rgw_nfs_namespace_expire_secs
;
1784 if (cmptime
< real_clock::to_timespec(now
)) {
1785 /* sets ctime as well as mtime, to avoid masking updates should
1786 * ctime inexplicably hold a higher value */
1791 void RGWFileHandle::invalidate() {
1792 RGWLibFS
*fs
= get_fs();
1793 if (fs
->invalidate_cb
) {
1794 fs
->invalidate_cb(fs
->invalidate_arg
, get_key().fh_hk
);
1798 int RGWWriteRequest::exec_start() {
1799 struct req_state
* state
= get_state();
1801 /* Object needs a bucket from this point */
1802 state
->object
->set_bucket(state
->bucket
.get());
1804 auto compression_type
=
1805 get_store()->svc()->zone
->get_zone_params().get_compression_type(
1806 state
->bucket
->get_placement_rule());
1808 /* not obviously supportable */
1809 ceph_assert(! dlo_manifest
);
1810 ceph_assert(! slo_info
);
1812 perfcounter
->inc(l_rgw_put
);
1815 if (state
->object
->empty()) {
1816 ldout(state
->cct
, 0) << __func__
<< " called on empty object" << dendl
;
1820 op_ret
= get_params(null_yield
);
1824 op_ret
= get_system_versioning_params(state
, &olh_epoch
, &version_id
);
1829 /* user-supplied MD5 check skipped (not supplied) */
1830 /* early quota check skipped--we don't have size yet */
1831 /* skipping user-supplied etag--we might have one in future, but
1832 * like data it and other attrs would arrive after open */
1834 aio
.emplace(state
->cct
->_conf
->rgw_put_obj_min_window_size
);
1836 if (state
->bucket
->versioning_enabled()) {
1837 if (!version_id
.empty()) {
1838 state
->object
->set_instance(version_id
);
1840 state
->object
->gen_rand_obj_instance_name();
1841 version_id
= state
->object
->get_instance();
1844 processor
.emplace(&*aio
, get_store(), state
->bucket
.get(),
1845 &state
->dest_placement
,
1846 state
->bucket_owner
.get_id(),
1847 *static_cast<RGWObjectCtx
*>(state
->obj_ctx
),
1848 state
->object
->clone(), olh_epoch
, state
->req_id
,
1849 this, state
->yield
);
1851 op_ret
= processor
->prepare(state
->yield
);
1853 ldout(state
->cct
, 20) << "processor->prepare() returned ret=" << op_ret
1857 filter
= &*processor
;
1858 if (compression_type
!= "none") {
1859 plugin
= Compressor::create(state
->cct
, compression_type
);
1861 ldout(state
->cct
, 1) << "Cannot load plugin for rgw_compression_type "
1862 << compression_type
<< dendl
;
1864 compressor
.emplace(state
->cct
, plugin
, filter
);
1865 filter
= &*compressor
;
1873 int RGWWriteRequest::exec_continue()
1875 struct req_state
* state
= get_state();
1878 /* check guards (e.g., contig write) */
1880 ldout(state
->cct
, 5)
1881 << " chunks arrived in wrong order"
1882 << " (mounting with -o sync required)"
1887 op_ret
= state
->bucket
->check_quota(user_quota
, bucket_quota
, real_ofs
, null_yield
, true);
1888 /* max_size exceed */
1892 size_t len
= data
.length();
1896 hash
.Update((const unsigned char *)data
.c_str(), data
.length());
1897 op_ret
= filter
->process(std::move(data
), ofs
);
1901 bytes_written
+= len
;
1905 } /* exec_continue */
1907 int RGWWriteRequest::exec_finish()
1909 buffer::list bl
, aclbl
, ux_key
, ux_attrs
;
1910 map
<string
, string
>::iterator iter
;
1911 char calc_md5
[CEPH_CRYPTO_MD5_DIGESTSIZE
* 2 + 1];
1912 unsigned char m
[CEPH_CRYPTO_MD5_DIGESTSIZE
];
1913 struct req_state
* state
= get_state();
1915 size_t osize
= rgw_fh
->get_size();
1916 struct timespec octime
= rgw_fh
->get_ctime();
1917 struct timespec omtime
= rgw_fh
->get_mtime();
1918 real_time appx_t
= real_clock::now();
1920 state
->obj_size
= bytes_written
;
1921 perfcounter
->inc(l_rgw_put_b
, state
->obj_size
);
1923 // flush data in filters
1924 op_ret
= filter
->process({}, state
->obj_size
);
1929 op_ret
= state
->bucket
->check_quota(user_quota
, bucket_quota
, state
->obj_size
, null_yield
, true);
1930 /* max_size exceed */
1937 if (compressor
&& compressor
->is_compressed()) {
1939 RGWCompressionInfo cs_info
;
1940 cs_info
.compression_type
= plugin
->get_type_name();
1941 cs_info
.orig_size
= state
->obj_size
;
1942 cs_info
.blocks
= std::move(compressor
->get_compression_blocks());
1943 encode(cs_info
, tmp
);
1944 attrs
[RGW_ATTR_COMPRESSION
] = tmp
;
1945 ldpp_dout(this, 20) << "storing " << RGW_ATTR_COMPRESSION
1946 << " with type=" << cs_info
.compression_type
1947 << ", orig_size=" << cs_info
.orig_size
1948 << ", blocks=" << cs_info
.blocks
.size() << dendl
;
1951 buf_to_hex(m
, CEPH_CRYPTO_MD5_DIGESTSIZE
, calc_md5
);
1954 bl
.append(etag
.c_str(), etag
.size() + 1);
1955 emplace_attr(RGW_ATTR_ETAG
, std::move(bl
));
1957 policy
.encode(aclbl
);
1958 emplace_attr(RGW_ATTR_ACL
, std::move(aclbl
));
1961 rgw_fh
->set_mtime(real_clock::to_timespec(appx_t
));
1962 rgw_fh
->set_ctime(real_clock::to_timespec(appx_t
));
1963 rgw_fh
->set_size(bytes_written
);
1964 rgw_fh
->encode_attrs(ux_key
, ux_attrs
);
1966 emplace_attr(RGW_ATTR_UNIX_KEY1
, std::move(ux_key
));
1967 emplace_attr(RGW_ATTR_UNIX1
, std::move(ux_attrs
));
1969 for (iter
= state
->generic_attrs
.begin(); iter
!= state
->generic_attrs
.end();
1971 buffer::list
& attrbl
= attrs
[iter
->first
];
1972 const string
& val
= iter
->second
;
1973 attrbl
.append(val
.c_str(), val
.size() + 1);
1976 op_ret
= rgw_get_request_metadata(this, state
->cct
, state
->info
, attrs
);
1980 encode_delete_at_attr(delete_at
, attrs
);
1982 /* Add a custom metadata to expose the information whether an object
1983 * is an SLO or not. Appending the attribute must be performed AFTER
1984 * processing any input from user in order to prohibit overwriting. */
1985 if (unlikely(!! slo_info
)) {
1986 buffer::list slo_userindicator_bl
;
1988 encode("True", slo_userindicator_bl
);
1989 emplace_attr(RGW_ATTR_SLO_UINDICATOR
, std::move(slo_userindicator_bl
));
1992 op_ret
= processor
->complete(state
->obj_size
, etag
, &mtime
, real_time(), attrs
,
1993 (delete_at
? *delete_at
: real_time()),
1994 if_match
, if_nomatch
, nullptr, nullptr, nullptr,
1997 /* revert attr updates */
1998 rgw_fh
->set_mtime(omtime
);
1999 rgw_fh
->set_ctime(octime
);
2000 rgw_fh
->set_size(osize
);
2004 perfcounter
->tinc(l_rgw_put_lat
, state
->time_elapsed());
2008 } /* namespace rgw */
2013 void rgwfile_version(int *major
, int *minor
, int *extra
)
2016 *major
= LIBRGW_FILE_VER_MAJOR
;
2018 *minor
= LIBRGW_FILE_VER_MINOR
;
2020 *extra
= LIBRGW_FILE_VER_EXTRA
;
2024 attach rgw namespace
2026 int rgw_mount(librgw_t rgw
, const char *uid
, const char *acc_key
,
2027 const char *sec_key
, struct rgw_fs
**rgw_fs
,
2032 /* stash access data for "mount" */
2033 RGWLibFS
* new_fs
= new RGWLibFS(static_cast<CephContext
*>(rgw
), uid
, acc_key
,
2035 ceph_assert(new_fs
);
2037 const DoutPrefix
dp(rgwlib
.get_store()->ctx(), dout_subsys
, "rgw mount: ");
2038 rc
= new_fs
->authorize(&dp
, rgwlib
.get_store());
2044 /* register fs for shared gc */
2045 rgwlib
.get_fe()->get_process()->register_fs(new_fs
);
2047 struct rgw_fs
*fs
= new_fs
->get_fs();
2050 /* XXX we no longer assume "/" is unique, but we aren't tracking the
2058 int rgw_mount2(librgw_t rgw
, const char *uid
, const char *acc_key
,
2059 const char *sec_key
, const char *root
, struct rgw_fs
**rgw_fs
,
2064 /* stash access data for "mount" */
2065 RGWLibFS
* new_fs
= new RGWLibFS(static_cast<CephContext
*>(rgw
), uid
, acc_key
,
2067 ceph_assert(new_fs
);
2069 const DoutPrefix
dp(rgwlib
.get_store()->ctx(), dout_subsys
, "rgw mount2: ");
2070 rc
= new_fs
->authorize(&dp
, rgwlib
.get_store());
2076 /* register fs for shared gc */
2077 rgwlib
.get_fe()->get_process()->register_fs(new_fs
);
2079 struct rgw_fs
*fs
= new_fs
->get_fs();
2082 /* XXX we no longer assume "/" is unique, but we aren't tracking the
2091 register invalidate callbacks
2093 int rgw_register_invalidate(struct rgw_fs
*rgw_fs
, rgw_fh_callback_t cb
,
2094 void *arg
, uint32_t flags
)
2097 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2098 return fs
->register_invalidate(cb
, arg
, flags
);
2102 detach rgw namespace
2104 int rgw_umount(struct rgw_fs
*rgw_fs
, uint32_t flags
)
2106 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2112 get filesystem attributes
2114 int rgw_statfs(struct rgw_fs
*rgw_fs
,
2115 struct rgw_file_handle
*parent_fh
,
2116 struct rgw_statvfs
*vfs_st
, uint32_t flags
)
2118 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2119 struct rados_cluster_stat_t stats
;
2121 RGWGetClusterStatReq
req(fs
->get_context(),
2122 rgwlib
.get_store()->get_user(fs
->get_user()->user_id
),
2124 int rc
= rgwlib
.get_fe()->execute_req(&req
);
2126 lderr(fs
->get_context()) << "ERROR: getting total cluster usage"
2127 << cpp_strerror(-rc
) << dendl
;
2131 //Set block size to 1M.
2132 constexpr uint32_t CEPH_BLOCK_SHIFT
= 20;
2133 vfs_st
->f_bsize
= 1 << CEPH_BLOCK_SHIFT
;
2134 vfs_st
->f_frsize
= 1 << CEPH_BLOCK_SHIFT
;
2135 vfs_st
->f_blocks
= stats
.kb
>> (CEPH_BLOCK_SHIFT
- 10);
2136 vfs_st
->f_bfree
= stats
.kb_avail
>> (CEPH_BLOCK_SHIFT
- 10);
2137 vfs_st
->f_bavail
= stats
.kb_avail
>> (CEPH_BLOCK_SHIFT
- 10);
2138 vfs_st
->f_files
= stats
.num_objects
;
2139 vfs_st
->f_ffree
= -1;
2140 vfs_st
->f_fsid
[0] = fs
->get_fsid();
2141 vfs_st
->f_fsid
[1] = fs
->get_fsid();
2143 vfs_st
->f_namemax
= 4096;
2148 generic create -- create an empty regular file
2150 int rgw_create(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*parent_fh
,
2151 const char *name
, struct stat
*st
, uint32_t mask
,
2152 struct rgw_file_handle
**fh
, uint32_t posix_flags
,
2157 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2158 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
2161 (parent
->is_root()) ||
2162 (parent
->is_file())) {
2167 MkObjResult fhr
= fs
->create(parent
, name
, st
, mask
, flags
);
2168 RGWFileHandle
*nfh
= get
<0>(fhr
); // nullptr if !success
2171 *fh
= nfh
->get_fh();
2177 create a symbolic link
2179 int rgw_symlink(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*parent_fh
,
2180 const char *name
, const char *link_path
, struct stat
*st
, uint32_t mask
,
2181 struct rgw_file_handle
**fh
, uint32_t posix_flags
,
2186 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2187 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
2190 (parent
->is_root()) ||
2191 (parent
->is_file())) {
2196 MkObjResult fhr
= fs
->symlink(parent
, name
, link_path
, st
, mask
, flags
);
2197 RGWFileHandle
*nfh
= get
<0>(fhr
); // nullptr if !success
2200 *fh
= nfh
->get_fh();
2206 create a new directory
2208 int rgw_mkdir(struct rgw_fs
*rgw_fs
,
2209 struct rgw_file_handle
*parent_fh
,
2210 const char *name
, struct stat
*st
, uint32_t mask
,
2211 struct rgw_file_handle
**fh
, uint32_t flags
)
2215 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2216 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
2223 MkObjResult fhr
= fs
->mkdir(parent
, name
, st
, mask
, flags
);
2224 RGWFileHandle
*nfh
= get
<0>(fhr
); // nullptr if !success
2227 *fh
= nfh
->get_fh();
2235 int rgw_rename(struct rgw_fs
*rgw_fs
,
2236 struct rgw_file_handle
*src
, const char* src_name
,
2237 struct rgw_file_handle
*dst
, const char* dst_name
,
2240 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2242 RGWFileHandle
* src_fh
= get_rgwfh(src
);
2243 RGWFileHandle
* dst_fh
= get_rgwfh(dst
);
2245 return fs
->rename(src_fh
, dst_fh
, src_name
, dst_name
);
2249 remove file or directory
2251 int rgw_unlink(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*parent_fh
,
2252 const char *name
, uint32_t flags
)
2254 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2255 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
2257 return fs
->unlink(parent
, name
);
2261 lookup object by name (POSIX style)
2263 int rgw_lookup(struct rgw_fs
*rgw_fs
,
2264 struct rgw_file_handle
*parent_fh
, const char* path
,
2265 struct rgw_file_handle
**fh
,
2266 struct stat
*st
, uint32_t mask
, uint32_t flags
)
2268 //CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
2269 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2271 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
2273 (! parent
->is_dir())) {
2278 RGWFileHandle
* rgw_fh
;
2281 if (parent
->is_root()) {
2282 /* special: parent lookup--note lack of ref()! */
2283 if (unlikely((strcmp(path
, "..") == 0) ||
2284 (strcmp(path
, "/") == 0))) {
2287 RGWLibFS::BucketStats bstat
;
2288 fhr
= fs
->stat_bucket(parent
, path
, bstat
, RGWFileHandle::FLAG_NONE
);
2289 rgw_fh
= get
<0>(fhr
);
2294 /* special: after readdir--note extra ref()! */
2295 if (unlikely((strcmp(path
, "..") == 0))) {
2297 lsubdout(fs
->get_context(), rgw
, 17)
2298 << __func__
<< " BANG"<< *rgw_fh
2302 enum rgw_fh_type fh_type
= fh_type_of(flags
);
2304 uint32_t sl_flags
= (flags
& RGW_LOOKUP_FLAG_RCB
)
2305 ? RGWFileHandle::FLAG_IN_CB
2306 : RGWFileHandle::FLAG_EXACT_MATCH
;
2308 bool fast_attrs
= fs
->get_context()->_conf
->rgw_nfs_s3_fast_attrs
;
2310 if ((flags
& RGW_LOOKUP_FLAG_RCB
) && fast_attrs
) {
2311 /* FAKE STAT--this should mean, interpolate special
2312 * owner, group, and perms masks */
2313 fhr
= fs
->fake_leaf(parent
, path
, fh_type
, st
, mask
, sl_flags
);
2315 if ((fh_type
== RGW_FS_TYPE_DIRECTORY
) && fast_attrs
) {
2316 /* trust cached dir, if present */
2317 fhr
= fs
->lookup_fh(parent
, path
, RGWFileHandle::FLAG_DIRECTORY
);
2319 rgw_fh
= get
<0>(fhr
);
2323 fhr
= fs
->stat_leaf(parent
, path
, fh_type
, sl_flags
);
2325 if (! get
<0>(fhr
)) {
2326 if (! (flags
& RGW_LOOKUP_FLAG_CREATE
))
2329 fhr
= fs
->lookup_fh(parent
, path
, RGWFileHandle::FLAG_CREATE
);
2331 rgw_fh
= get
<0>(fhr
);
2336 struct rgw_file_handle
*rfh
= rgw_fh
->get_fh();
2343 lookup object by handle (NFS style)
2345 int rgw_lookup_handle(struct rgw_fs
*rgw_fs
, struct rgw_fh_hk
*fh_hk
,
2346 struct rgw_file_handle
**fh
, uint32_t flags
)
2348 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2350 RGWFileHandle
* rgw_fh
= fs
->lookup_handle(*fh_hk
);
2356 struct rgw_file_handle
*rfh
= rgw_fh
->get_fh();
2363 * release file handle
2365 int rgw_fh_rele(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
2368 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2369 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2371 lsubdout(fs
->get_context(), rgw
, 17)
2372 << __func__
<< " " << *rgw_fh
2380 get unix attributes for object
2382 int rgw_getattr(struct rgw_fs
*rgw_fs
,
2383 struct rgw_file_handle
*fh
, struct stat
*st
, uint32_t flags
)
2385 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2386 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2388 return fs
->getattr(rgw_fh
, st
);
2392 set unix attributes for object
2394 int rgw_setattr(struct rgw_fs
*rgw_fs
,
2395 struct rgw_file_handle
*fh
, struct stat
*st
,
2396 uint32_t mask
, uint32_t flags
)
2398 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2399 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2401 return fs
->setattr(rgw_fh
, st
, mask
, flags
);
2407 int rgw_truncate(struct rgw_fs
*rgw_fs
,
2408 struct rgw_file_handle
*fh
, uint64_t size
, uint32_t flags
)
2416 int rgw_open(struct rgw_fs
*rgw_fs
,
2417 struct rgw_file_handle
*fh
, uint32_t posix_flags
, uint32_t flags
)
2419 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2422 * need to track specific opens--at least read opens and
2423 * a write open; we need to know when a write open is returned,
2424 * that closes a write transaction
2426 * for now, we will support single-open only, it's preferable to
2427 * anything we can otherwise do without access to the NFS state
2429 if (! rgw_fh
->is_file())
2432 return rgw_fh
->open(flags
);
2438 int rgw_close(struct rgw_fs
*rgw_fs
,
2439 struct rgw_file_handle
*fh
, uint32_t flags
)
2441 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2442 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2443 int rc
= rgw_fh
->close(/* XXX */);
2445 if (flags
& RGW_CLOSE_FLAG_RELE
)
2451 int rgw_readdir(struct rgw_fs
*rgw_fs
,
2452 struct rgw_file_handle
*parent_fh
, uint64_t *offset
,
2453 rgw_readdir_cb rcb
, void *cb_arg
, bool *eof
,
2456 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
2462 lsubdout(parent
->get_fs()->get_context(), rgw
, 15)
2464 << " offset=" << *offset
2467 if ((*offset
== 0) &&
2468 (flags
& RGW_READDIR_FLAG_DOTDOT
)) {
2469 /* send '.' and '..' with their NFS-defined offsets */
2470 rcb(".", cb_arg
, 1, nullptr, 0, RGW_LOOKUP_FLAG_DIR
);
2471 rcb("..", cb_arg
, 2, nullptr, 0, RGW_LOOKUP_FLAG_DIR
);
2474 int rc
= parent
->readdir(rcb
, cb_arg
, offset
, eof
, flags
);
2478 /* enumeration continuing from name */
2479 int rgw_readdir2(struct rgw_fs
*rgw_fs
,
2480 struct rgw_file_handle
*parent_fh
, const char *name
,
2481 rgw_readdir_cb rcb
, void *cb_arg
, bool *eof
,
2484 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
2490 lsubdout(parent
->get_fs()->get_context(), rgw
, 15)
2492 << " offset=" << ((name
) ? name
: "(nil)")
2496 (flags
& RGW_READDIR_FLAG_DOTDOT
)) {
2497 /* send '.' and '..' with their NFS-defined offsets */
2498 rcb(".", cb_arg
, 1, nullptr, 0, RGW_LOOKUP_FLAG_DIR
);
2499 rcb("..", cb_arg
, 2, nullptr, 0, RGW_LOOKUP_FLAG_DIR
);
2502 int rc
= parent
->readdir(rcb
, cb_arg
, name
, eof
, flags
);
2504 } /* rgw_readdir2 */
2506 /* project offset of dirent name */
2507 int rgw_dirent_offset(struct rgw_fs
*rgw_fs
,
2508 struct rgw_file_handle
*parent_fh
,
2509 const char *name
, int64_t *offset
,
2512 RGWFileHandle
* parent
= get_rgwfh(parent_fh
);
2517 std::string sname
{name
};
2518 int rc
= parent
->offset_of(sname
, offset
, flags
);
2525 int rgw_read(struct rgw_fs
*rgw_fs
,
2526 struct rgw_file_handle
*fh
, uint64_t offset
,
2527 size_t length
, size_t *bytes_read
, void *buffer
,
2530 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2531 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2533 return fs
->read(rgw_fh
, offset
, length
, bytes_read
, buffer
, flags
);
2539 int rgw_readlink(struct rgw_fs
*rgw_fs
,
2540 struct rgw_file_handle
*fh
, uint64_t offset
,
2541 size_t length
, size_t *bytes_read
, void *buffer
,
2544 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2545 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2547 return fs
->readlink(rgw_fh
, offset
, length
, bytes_read
, buffer
, flags
);
2553 int rgw_write(struct rgw_fs
*rgw_fs
,
2554 struct rgw_file_handle
*fh
, uint64_t offset
,
2555 size_t length
, size_t *bytes_written
, void *buffer
,
2558 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2563 if (! rgw_fh
->is_file())
2566 if (! rgw_fh
->is_open()) {
2567 if (flags
& RGW_OPEN_FLAG_V3
) {
2568 rc
= rgw_fh
->open(flags
);
2575 rc
= rgw_fh
->write(offset
, length
, bytes_written
, buffer
);
2581 read data from file (vector)
2586 struct rgw_vio
* vio
;
2589 RGWReadV(buffer::list
& _bl
, rgw_vio
* _vio
) : vio(_vio
) {
2590 bl
= std::move(_bl
);
2593 struct rgw_vio
* get_vio() { return vio
; }
2595 const auto& buffers() { return bl
.buffers(); }
2597 unsigned /* XXX */ length() { return bl
.length(); }
2601 void rgw_readv_rele(struct rgw_uio
*uio
, uint32_t flags
)
2603 RGWReadV
* rdv
= static_cast<RGWReadV
*>(uio
->uio_p1
);
2605 ::operator delete(rdv
);
2608 int rgw_readv(struct rgw_fs
*rgw_fs
,
2609 struct rgw_file_handle
*fh
, rgw_uio
*uio
, uint32_t flags
)
2612 CephContext
* cct
= static_cast<CephContext
*>(rgw_fs
->rgw
);
2613 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2614 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2616 if (! rgw_fh
->is_file())
2622 RGWGetObjRequest
req(cct
, fs
->get_user(), rgw_fh
->bucket_name(),
2623 rgw_fh
->object_name(), uio
->uio_offset
, uio
->uio_resid
,
2625 req
.do_hexdump
= false;
2627 rc
= rgwlib
.get_fe()->execute_req(&req
);
2630 RGWReadV
* rdv
= static_cast<RGWReadV
*>(
2631 ::operator new(sizeof(RGWReadV
) +
2632 (bl
.buffers().size() * sizeof(struct rgw_vio
))));
2635 RGWReadV(bl
, reinterpret_cast<rgw_vio
*>(rdv
+sizeof(RGWReadV
)));
2638 uio
->uio_cnt
= rdv
->buffers().size();
2639 uio
->uio_resid
= rdv
->length();
2640 uio
->uio_vio
= rdv
->get_vio();
2641 uio
->uio_rele
= rgw_readv_rele
;
2644 auto& buffers
= rdv
->buffers();
2645 for (auto& bp
: buffers
) {
2646 rgw_vio
*vio
= &(uio
->uio_vio
[ix
]);
2647 vio
->vio_base
= const_cast<char*>(bp
.c_str());
2648 vio
->vio_len
= bp
.length();
2649 vio
->vio_u1
= nullptr;
2650 vio
->vio_p1
= nullptr;
2662 write data to file (vector)
2664 int rgw_writev(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
2665 rgw_uio
*uio
, uint32_t flags
)
2668 // not supported - rest of function is ignored
2671 CephContext
* cct
= static_cast<CephContext
*>(rgw_fs
->rgw
);
2672 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2673 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2675 if (! rgw_fh
->is_file())
2679 for (unsigned int ix
= 0; ix
< uio
->uio_cnt
; ++ix
) {
2680 rgw_vio
*vio
= &(uio
->uio_vio
[ix
]);
2682 buffer::create_static(vio
->vio_len
,
2683 static_cast<char*>(vio
->vio_base
)));
2686 std::string oname
= rgw_fh
->relative_object_name();
2687 RGWPutObjRequest
req(cct
, rgwlib
.get_store()->get_user(fs
->get_user()->user_id
),
2688 rgw_fh
->bucket_name(), oname
, bl
);
2690 int rc
= rgwlib
.get_fe()->execute_req(&req
);
2692 /* XXX update size (in request) */
2700 int rgw_fsync(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*handle
,
2706 int rgw_commit(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
2707 uint64_t offset
, uint64_t length
, uint32_t flags
)
2709 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2711 return rgw_fh
->commit(offset
, length
, RGWFileHandle::FLAG_NONE
);
2718 int rgw_getxattrs(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
2719 rgw_xattrlist
*attrs
, rgw_getxattr_cb cb
, void *cb_arg
,
2722 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2723 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2725 return fs
->getxattrs(rgw_fh
, attrs
, cb
, cb_arg
, flags
);
2728 int rgw_lsxattrs(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
2729 rgw_xattrstr
*filter_prefix
/* ignored */,
2730 rgw_getxattr_cb cb
, void *cb_arg
, uint32_t flags
)
2732 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2733 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2735 return fs
->lsxattrs(rgw_fh
, filter_prefix
, cb
, cb_arg
, flags
);
2738 int rgw_setxattrs(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
2739 rgw_xattrlist
*attrs
, uint32_t flags
)
2741 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2742 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2744 return fs
->setxattrs(rgw_fh
, attrs
, flags
);
2747 int rgw_rmxattrs(struct rgw_fs
*rgw_fs
, struct rgw_file_handle
*fh
,
2748 rgw_xattrlist
*attrs
, uint32_t flags
)
2750 RGWLibFS
*fs
= static_cast<RGWLibFS
*>(rgw_fs
->fs_private
);
2751 RGWFileHandle
* rgw_fh
= get_rgwfh(fh
);
2753 return fs
->rmxattrs(rgw_fh
, attrs
, flags
);