]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_file.cc
import ceph pacific 16.2.5
[ceph.git] / ceph / src / rgw / rgw_file.cc
CommitLineData
7c673cae 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
7c673cae
FG
3
4#include "include/compat.h"
5#include "include/rados/rgw_file.h"
6
7#include <sys/types.h>
8#include <sys/stat.h>
9
10#include "rgw_lib.h"
7c673cae
FG
11#include "rgw_resolve.h"
12#include "rgw_op.h"
13#include "rgw_rest.h"
14#include "rgw_acl.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"
23#include "rgw_user.h"
24#include "rgw_bucket.h"
11fdf7f2 25#include "rgw_zone.h"
7c673cae
FG
26#include "rgw_file.h"
27#include "rgw_lib_frontend.h"
11fdf7f2 28#include "rgw_perf_counters.h"
28e407b8 29#include "common/errno.h"
7c673cae 30
9f95a23c
TL
31#include "services/svc_zone.h"
32
7c673cae
FG
33#include <atomic>
34
35#define dout_subsys ceph_subsys_rgw
36
37using namespace rgw;
38
39namespace rgw {
40
41 extern RGWLib rgwlib;
42
43 const string RGWFileHandle::root_name = "/";
44
45 std::atomic<uint32_t> RGWLibFS::fs_inst_counter;
46
47 uint32_t RGWLibFS::write_completion_interval_s = 10;
48
49 ceph::timer<ceph::mono_clock> RGWLibFS::write_timer{
50 ceph::construct_suspended};
51
52 inline int valid_fs_bucket_name(const string& name) {
53 int rc = valid_s3_bucket_name(name, false /* relaxed */);
54 if (rc != 0) {
55 if (name.size() > 255)
56 return -ENAMETOOLONG;
57 return -EINVAL;
58 }
59 return 0;
60 }
61
62 inline int valid_fs_object_name(const string& name) {
63 int rc = valid_s3_object_name(name);
64 if (rc != 0) {
65 if (name.size() > 1024)
66 return -ENAMETOOLONG;
67 return -EINVAL;
68 }
69 return 0;
70 }
71
f67539c2
TL
72 class XattrHash
73 {
74 public:
75 std::size_t operator()(const rgw_xattrstr& att) const noexcept {
76 return XXH64(att.val, att.len, 5882300);
77 }
78 };
79
80 class XattrEqual
81 {
82 public:
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));
86 }
87 };
88
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}
93 };
94
95 static inline bool is_exposed_attr(const rgw_xattrstr& k) {
96 return (rgw_exposed_attrs.find(k) != rgw_exposed_attrs.end());
97 }
98
31f18b77
FG
99 LookupFHResult RGWLibFS::stat_bucket(RGWFileHandle* parent, const char *path,
100 RGWLibFS::BucketStats& bs,
101 uint32_t flags)
7c673cae
FG
102 {
103 LookupFHResult fhr{nullptr, 0};
104 std::string bucket_name{path};
f67539c2 105 RGWStatBucketRequest req(cct, rgwlib.get_store()->get_user(user.user_id), bucket_name, bs);
7c673cae
FG
106
107 int rc = rgwlib.get_fe()->execute_req(&req);
108 if ((rc == 0) &&
109 (req.get_ret() == 0) &&
110 (req.matched())) {
111 fhr = lookup_fh(parent, path,
31f18b77 112 (flags & RGWFileHandle::FLAG_LOCKED)|
7c673cae
FG
113 RGWFileHandle::FLAG_CREATE|
114 RGWFileHandle::FLAG_BUCKET);
115 if (get<0>(fhr)) {
116 RGWFileHandle* rgw_fh = get<0>(fhr);
31f18b77
FG
117 if (! (flags & RGWFileHandle::FLAG_LOCKED)) {
118 rgw_fh->mtx.lock();
119 }
7c673cae
FG
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) {
3efd9988
FG
125 DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
126 if (get<0>(dar) || get<1>(dar)) {
127 update_fh(rgw_fh);
128 }
7c673cae 129 }
31f18b77
FG
130 if (! (flags & RGWFileHandle::FLAG_LOCKED)) {
131 rgw_fh->mtx.unlock();
132 }
7c673cae
FG
133 }
134 }
135 return fhr;
136 }
137
eafe8130
TL
138 LookupFHResult RGWLibFS::fake_leaf(RGWFileHandle* parent,
139 const char *path,
140 enum rgw_fh_type type,
141 struct stat *st, uint32_t st_mask,
142 uint32_t flags)
143 {
144 /* synthesize a minimal handle from parent, path, type, and st */
145 using std::get;
146
147 flags |= RGWFileHandle::FLAG_CREATE;
148
149 switch (type) {
150 case RGW_FS_TYPE_DIRECTORY:
151 flags |= RGWFileHandle::FLAG_DIRECTORY;
152 break;
153 default:
154 /* file */
155 break;
156 };
157
158 LookupFHResult fhr = lookup_fh(parent, path, flags);
159 if (get<0>(fhr)) {
160 RGWFileHandle* rgw_fh = get<0>(fhr);
161 if (st) {
162 lock_guard guard(rgw_fh->mtx);
163 if (st_mask & RGW_SETATTR_SIZE) {
164 rgw_fh->set_size(st->st_size);
165 }
166 if (st_mask & RGW_SETATTR_MTIME) {
167 rgw_fh->set_times(st->st_mtim);
168 }
169 } /* st */
170 } /* rgw_fh */
171 return fhr;
172 } /* RGWLibFS::fake_leaf */
173
7c673cae
FG
174 LookupFHResult RGWLibFS::stat_leaf(RGWFileHandle* parent,
175 const char *path,
176 enum rgw_fh_type type,
177 uint32_t flags)
178 {
179 /* find either-of <object_name>, <object_name/>, only one of
180 * which should exist; atomicity? */
181 using std::get;
182
183 LookupFHResult fhr{nullptr, 0};
184
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 */
189
31f18b77 190 std::string obj_path = parent->format_child_name(path, false);
7c673cae
FG
191
192 for (auto ix : { 0, 1, 2 }) {
193 switch (ix) {
194 case 0:
195 {
196 /* type hint */
197 if (type == RGW_FS_TYPE_DIRECTORY)
198 continue;
199
f67539c2 200 RGWStatObjRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
7c673cae
FG
201 parent->bucket_name(), obj_path,
202 RGWStatObjRequest::FLAG_NONE);
203 int rc = rgwlib.get_fe()->execute_req(&req);
204 if ((rc == 0) &&
205 (req.get_ret() == 0)) {
206 fhr = lookup_fh(parent, path, RGWFileHandle::FLAG_CREATE);
207 if (get<0>(fhr)) {
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);
81eedcae
TL
215 rgw_fh->set_etag(*(req.get_attr(RGW_ATTR_ETAG)));
216 rgw_fh->set_acls(*(req.get_attr(RGW_ATTR_ACL)));
f67539c2
TL
217 if (!(flags & RGWFileHandle::FLAG_IN_CB) &&
218 ux_key && ux_attrs) {
3efd9988
FG
219 DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
220 if (get<0>(dar) || get<1>(dar)) {
221 update_fh(rgw_fh);
222 }
7c673cae
FG
223 }
224 }
225 goto done;
226 }
227 }
228 break;
229 case 1:
230 {
231 /* try dir form */
232 /* type hint */
233 if (type == RGW_FS_TYPE_FILE)
234 continue;
235
236 obj_path += "/";
f67539c2 237 RGWStatObjRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
7c673cae
FG
238 parent->bucket_name(), obj_path,
239 RGWStatObjRequest::FLAG_NONE);
240 int rc = rgwlib.get_fe()->execute_req(&req);
241 if ((rc == 0) &&
242 (req.get_ret() == 0)) {
243 fhr = lookup_fh(parent, path, RGWFileHandle::FLAG_DIRECTORY);
244 if (get<0>(fhr)) {
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);
81eedcae
TL
252 rgw_fh->set_etag(*(req.get_attr(RGW_ATTR_ETAG)));
253 rgw_fh->set_acls(*(req.get_attr(RGW_ATTR_ACL)));
f67539c2
TL
254 if (!(flags & RGWFileHandle::FLAG_IN_CB) &&
255 ux_key && ux_attrs) {
3efd9988
FG
256 DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
257 if (get<0>(dar) || get<1>(dar)) {
258 update_fh(rgw_fh);
259 }
7c673cae
FG
260 }
261 }
262 goto done;
263 }
264 }
265 break;
266 case 2:
267 {
268 std::string object_name{path};
f67539c2
TL
269 RGWStatLeafRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
270 parent, object_name);
7c673cae
FG
271 int rc = rgwlib.get_fe()->execute_req(&req);
272 if ((rc == 0) &&
273 (req.get_ret() == 0)) {
274 if (req.matched) {
275 /* we need rgw object's key name equal to file name, if
276 * not return NULL */
277 if ((flags & RGWFileHandle::FLAG_EXACT_MATCH) &&
278 !req.exact_matched) {
279 lsubdout(get_context(), rgw, 15)
280 << __func__
281 << ": stat leaf not exact match file name = "
282 << path << dendl;
283 goto done;
284 }
285 fhr = lookup_fh(parent, path,
286 RGWFileHandle::FLAG_CREATE|
287 ((req.is_dir) ?
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 */
294 if (get<0>(fhr)) {
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());
299 }
300 }
301 }
302 }
303 break;
304 default:
305 /* not reached */
306 break;
307 }
308 }
309 done:
310 return fhr;
311 } /* RGWLibFS::stat_leaf */
312
313 int RGWLibFS::read(RGWFileHandle* rgw_fh, uint64_t offset, size_t length,
314 size_t* bytes_read, void* buffer, uint32_t flags)
315 {
316 if (! rgw_fh->is_file())
317 return -EINVAL;
318
319 if (rgw_fh->deleted())
320 return -ESTALE;
321
f67539c2
TL
322 RGWReadRequest req(get_context(), rgwlib.get_store()->get_user(user.user_id),
323 rgw_fh, offset, length, buffer);
7c673cae
FG
324
325 int rc = rgwlib.get_fe()->execute_req(&req);
326 if ((rc == 0) &&
327 (req.get_ret() == 0)) {
11fdf7f2
TL
328 lock_guard guard(rgw_fh->mtx);
329 rgw_fh->set_atime(real_clock::to_timespec(real_clock::now()));
330 *bytes_read = req.nread;
331 }
332
333 return rc;
334 }
335
336 int RGWLibFS::readlink(RGWFileHandle* rgw_fh, uint64_t offset, size_t length,
337 size_t* bytes_read, void* buffer, uint32_t flags)
338 {
339 if (! rgw_fh->is_link())
340 return -EINVAL;
341
342 if (rgw_fh->deleted())
343 return -ESTALE;
344
f67539c2
TL
345 RGWReadRequest req(get_context(), rgwlib.get_store()->get_user(user.user_id),
346 rgw_fh, offset, length, buffer);
11fdf7f2
TL
347
348 int rc = rgwlib.get_fe()->execute_req(&req);
349 if ((rc == 0) &&
350 (req.get_ret() == 0)) {
7c673cae
FG
351 lock_guard(rgw_fh->mtx);
352 rgw_fh->set_atime(real_clock::to_timespec(real_clock::now()));
353 *bytes_read = req.nread;
354 }
355
356 return rc;
357 }
358
359 int RGWLibFS::unlink(RGWFileHandle* rgw_fh, const char* name, uint32_t flags)
360 {
361 int rc = 0;
31f18b77 362 BucketStats bs;
7c673cae 363 RGWFileHandle* parent = nullptr;
31f18b77 364 RGWFileHandle* bkt_fh = nullptr;
7c673cae
FG
365
366 if (unlikely(flags & RGWFileHandle::FLAG_UNLINK_THIS)) {
367 /* LOCKED */
368 parent = rgw_fh->get_parent();
369 } else {
370 /* atomicity */
371 parent = rgw_fh;
372 LookupFHResult fhr = lookup_fh(parent, name, RGWFileHandle::FLAG_LOCK);
373 rgw_fh = get<0>(fhr);
374 /* LOCKED */
375 }
376
377 if (parent->is_root()) {
31f18b77
FG
378 /* a bucket may have an object storing Unix attributes, check
379 * for and delete it */
380 LookupFHResult fhr;
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 */
387 return -ENOENT;
388 }
389
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
394 * special case of
395 * RGWFileHandle::FLAG_UNLINK_THIS) */
396 rgw_fh->mtx.unlock();
397 unref(rgw_fh);
398 }
399 return -ENOTEMPTY;
400 } else {
401 /* delete object w/key "<bucket>/" (uxattrs), if any */
402 string oname{"/"};
f67539c2
TL
403 RGWDeleteObjRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
404 bkt_fh->bucket_name(), oname);
31f18b77
FG
405 rc = rgwlib.get_fe()->execute_req(&req);
406 /* don't care if ENOENT */
407 unref(bkt_fh);
408 }
409
410 string bname{name};
f67539c2 411 RGWDeleteBucketRequest req(cct, rgwlib.get_store()->get_user(user.user_id), bname);
7c673cae
FG
412 rc = rgwlib.get_fe()->execute_req(&req);
413 if (! rc) {
414 rc = req.get_ret();
415 }
416 } else {
417 /*
418 * leaf object
419 */
420 if (! rgw_fh) {
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,
eafe8130 426 nullptr /* st */, 0 /* mask */,
7c673cae
FG
427 RGW_LOOKUP_FLAG_NONE);
428 if (!! rc)
429 return rc;
430
431 /* rgw_fh ref+ */
432 rgw_fh = get_rgwfh(fh);
433 rgw_fh->mtx.lock(); /* LOCKED */
434 }
435
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
439 * child cache */
440 if (rgw_fh->has_children()) {
441 rgw_fh->mtx.unlock();
442 unref(rgw_fh);
443 return(-ENOTEMPTY);
444 }
445 oname += "/";
446 }
f67539c2 447 RGWDeleteObjRequest req(cct, rgwlib.get_store()->get_user(user.user_id), parent->bucket_name(),
7c673cae
FG
448 oname);
449 rc = rgwlib.get_fe()->execute_req(&req);
450 if (! rc) {
451 rc = req.get_ret();
452 }
453 }
454
31f18b77
FG
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);
460 }
7c673cae
FG
461
462 if (! rc) {
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));
466 }
467
468 rgw_fh->mtx.unlock();
469 unref(rgw_fh);
470
471 return rc;
472 } /* RGWLibFS::unlink */
473
474 int RGWLibFS::rename(RGWFileHandle* src_fh, RGWFileHandle* dst_fh,
475 const char *_src_name, const char *_dst_name)
476
477 {
478 /* XXX initial implementation: try-copy, and delete if copy
479 * succeeds */
480 int rc = -EINVAL;
7c673cae
FG
481 real_time t;
482
483 std::string src_name{_src_name};
484 std::string dst_name{_dst_name};
485
486 /* atomicity */
487 LookupFHResult fhr = lookup_fh(src_fh, _src_name, RGWFileHandle::FLAG_LOCK);
488 RGWFileHandle* rgw_fh = get<0>(fhr);
489
490 /* should not happen */
491 if (! rgw_fh) {
492 ldout(get_context(), 0) << __func__
493 << " BUG no such src renaming path="
494 << src_name
495 << dendl;
496 goto out;
497 }
498
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()
504 << dendl;
505 rc = -EPERM;
506 goto unlock;
507 }
508
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()
514 << dendl;
515 rc = -EPERM;
516 goto unlock;
517 }
518
519 t = real_clock::now();
520
521 for (int ix : {0, 1}) {
522 switch (ix) {
523 case 0:
524 {
f67539c2
TL
525 RGWCopyObjRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
526 src_fh, dst_fh, src_name, dst_name);
7c673cae
FG
527 int rc = rgwlib.get_fe()->execute_req(&req);
528 if ((rc != 0) ||
529 ((rc = req.get_ret()) != 0)) {
530 ldout(get_context(), 1)
531 << __func__
532 << " rename step 0 failed src="
533 << src_fh->full_object_name() << " " << src_name
534 << " dst=" << dst_fh->full_object_name()
535 << " " << dst_name
536 << "rc " << rc
537 << dendl;
538 goto unlock;
539 }
540 ldout(get_context(), 12)
541 << __func__
542 << " rename step 0 success src="
543 << src_fh->full_object_name() << " " << src_name
544 << " dst=" << dst_fh->full_object_name()
545 << " " << dst_name
546 << " rc " << rc
547 << dendl;
548 /* update dst change id */
549 dst_fh->set_times(t);
550 }
551 break;
552 case 1:
553 {
554 rc = this->unlink(rgw_fh /* LOCKED */, _src_name,
555 RGWFileHandle::FLAG_UNLINK_THIS);
556 /* !LOCKED, -ref */
557 if (! rc) {
558 ldout(get_context(), 12)
559 << __func__
560 << " rename step 1 success src="
561 << src_fh->full_object_name() << " " << src_name
562 << " dst=" << dst_fh->full_object_name()
563 << " " << dst_name
564 << " rc " << rc
565 << dendl;
566 /* update src change id */
567 src_fh->set_times(t);
568 } else {
569 ldout(get_context(), 1)
570 << __func__
571 << " rename step 1 failed src="
572 << src_fh->full_object_name() << " " << src_name
573 << " dst=" << dst_fh->full_object_name()
574 << " " << dst_name
575 << " rc " << rc
576 << dendl;
577 }
578 }
579 goto out;
580 default:
11fdf7f2 581 ceph_abort();
7c673cae
FG
582 } /* switch */
583 } /* ix */
584 unlock:
585 rgw_fh->mtx.unlock(); /* !LOCKED */
586 unref(rgw_fh); /* -ref */
587
588 out:
589 return rc;
590 } /* RGWLibFS::rename */
591
592 MkObjResult RGWLibFS::mkdir(RGWFileHandle* parent, const char *name,
593 struct stat *st, uint32_t mask, uint32_t flags)
594 {
7c673cae 595 int rc, rc2;
31f18b77
FG
596 rgw_file_handle *lfh;
597
598 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh,
eafe8130 599 nullptr /* st */, 0 /* mask */,
31f18b77
FG
600 RGW_LOOKUP_FLAG_NONE);
601 if (! rc) {
602 /* conflict! */
603 rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE);
f67539c2 604 // ignore return code
31f18b77
FG
605 return MkObjResult{nullptr, -EEXIST};
606 }
7c673cae 607
31f18b77 608 MkObjResult mkr{nullptr, -EINVAL};
7c673cae
FG
609 LookupFHResult fhr;
610 RGWFileHandle* rgw_fh = nullptr;
611 buffer::list ux_key, ux_attrs;
612
613 fhr = lookup_fh(parent, name,
614 RGWFileHandle::FLAG_CREATE|
615 RGWFileHandle::FLAG_DIRECTORY|
616 RGWFileHandle::FLAG_LOCK);
617 rgw_fh = get<0>(fhr);
618 if (rgw_fh) {
619 rgw_fh->create_stat(st, mask);
620 rgw_fh->set_times(real_clock::now());
621 /* save attrs */
622 rgw_fh->encode_attrs(ux_key, ux_attrs);
623 if (st)
494da23a 624 rgw_fh->stat(st, RGWFileHandle::FLAG_LOCKED);
7c673cae
FG
625 get<0>(mkr) = rgw_fh;
626 } else {
627 get<1>(mkr) = -EIO;
628 return mkr;
629 }
630
631 if (parent->is_root()) {
632 /* bucket */
633 string bname{name};
634 /* enforce S3 name restrictions */
635 rc = valid_fs_bucket_name(bname);
636 if (rc != 0) {
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();
641 unref(rgw_fh);
642 get<0>(mkr) = nullptr;
643 get<1>(mkr) = rc;
644 return mkr;
645 }
646
f67539c2
TL
647 RGWCreateBucketRequest req(get_context(),
648 rgwlib.get_store()->get_user(user.user_id), bname);
7c673cae
FG
649
650 /* save attrs */
651 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
652 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
653
654 rc = rgwlib.get_fe()->execute_req(&req);
655 rc2 = req.get_ret();
656 } else {
657 /* create an object representing the directory */
658 buffer::list bl;
31f18b77 659 string dir_name = parent->format_child_name(name, true);
7c673cae
FG
660
661 /* need valid S3 name (characters, length <= 1024, etc) */
662 rc = valid_fs_object_name(dir_name);
663 if (rc != 0) {
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();
668 unref(rgw_fh);
669 get<0>(mkr) = nullptr;
670 get<1>(mkr) = rc;
671 return mkr;
672 }
673
f67539c2
TL
674 RGWPutObjRequest req(get_context(), rgwlib.get_store()->get_user(user.user_id),
675 parent->bucket_name(), dir_name, bl);
7c673cae
FG
676
677 /* save attrs */
678 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
679 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
680
681 rc = rgwlib.get_fe()->execute_req(&req);
682 rc2 = req.get_ret();
683 }
684
685 if (! ((rc == 0) &&
686 (rc2 == 0))) {
687 /* op failed */
688 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
689 rgw_fh->mtx.unlock(); /* !LOCKED */
690 unref(rgw_fh);
691 get<0>(mkr) = nullptr;
692 /* fixup rc */
693 if (!rc)
694 rc = rc2;
695 } else {
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 */
700 }
701
702 get<1>(mkr) = rc;
703
704 return mkr;
705 } /* RGWLibFS::mkdir */
706
707 MkObjResult RGWLibFS::create(RGWFileHandle* parent, const char *name,
708 struct stat *st, uint32_t mask, uint32_t flags)
709 {
710 int rc, rc2;
711
712 using std::get;
713
714 rgw_file_handle *lfh;
715 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh,
eafe8130 716 nullptr /* st */, 0 /* mask */,
7c673cae
FG
717 RGW_LOOKUP_FLAG_NONE);
718 if (! rc) {
719 /* conflict! */
720 rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE);
f67539c2 721 // ignore return code
7c673cae
FG
722 return MkObjResult{nullptr, -EEXIST};
723 }
724
725 /* expand and check name */
31f18b77 726 std::string obj_name = parent->format_child_name(name, false);
7c673cae
FG
727 rc = valid_fs_object_name(obj_name);
728 if (rc != 0) {
729 return MkObjResult{nullptr, rc};
730 }
731
732 /* create it */
733 buffer::list bl;
f67539c2
TL
734 RGWPutObjRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
735 parent->bucket_name(), obj_name, bl);
7c673cae
FG
736 MkObjResult mkr{nullptr, -EINVAL};
737
738 rc = rgwlib.get_fe()->execute_req(&req);
739 rc2 = req.get_ret();
740
741 if ((rc == 0) &&
742 (rc2 == 0)) {
743 /* XXX atomicity */
744 LookupFHResult fhr = lookup_fh(parent, name, RGWFileHandle::FLAG_CREATE |
745 RGWFileHandle::FLAG_LOCK);
746 RGWFileHandle* rgw_fh = get<0>(fhr);
747 if (rgw_fh) {
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);
753
754 parent->set_mtime(real_clock::to_timespec(t));
755 parent->set_ctime(real_clock::to_timespec(t));
756 }
757 if (st)
494da23a 758 (void) rgw_fh->stat(st, RGWFileHandle::FLAG_LOCKED);
81eedcae
TL
759
760 rgw_fh->set_etag(*(req.get_attr(RGW_ATTR_ETAG)));
761 rgw_fh->set_acls(*(req.get_attr(RGW_ATTR_ACL)));
762
7c673cae
FG
763 get<0>(mkr) = rgw_fh;
764 rgw_fh->mtx.unlock();
765 } else
766 rc = -EIO;
767 }
768
769 get<1>(mkr) = rc;
11fdf7f2
TL
770
771 /* case like : quota exceed will be considered as fail too*/
772 if(rc2 < 0)
773 get<1>(mkr) = rc2;
7c673cae
FG
774
775 return mkr;
776 } /* RGWLibFS::create */
777
11fdf7f2
TL
778 MkObjResult RGWLibFS::symlink(RGWFileHandle* parent, const char *name,
779 const char* link_path, struct stat *st, uint32_t mask, uint32_t flags)
780 {
781 int rc, rc2;
782
783 using std::get;
784
785 rgw_file_handle *lfh;
eafe8130
TL
786 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh,
787 nullptr /* st */, 0 /* mask */,
11fdf7f2
TL
788 RGW_LOOKUP_FLAG_NONE);
789 if (! rc) {
790 /* conflict! */
791 rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE);
f67539c2 792 // ignore return code
11fdf7f2
TL
793 return MkObjResult{nullptr, -EEXIST};
794 }
795
796 MkObjResult mkr{nullptr, -EINVAL};
797 LookupFHResult fhr;
798 RGWFileHandle* rgw_fh = nullptr;
799 buffer::list ux_key, ux_attrs;
800
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);
806 if (rgw_fh) {
807 rgw_fh->create_stat(st, mask);
808 rgw_fh->set_times(real_clock::now());
809 /* save attrs */
810 rgw_fh->encode_attrs(ux_key, ux_attrs);
811 if (st)
812 rgw_fh->stat(st);
813 get<0>(mkr) = rgw_fh;
814 } else {
815 get<1>(mkr) = -EIO;
816 return mkr;
817 }
818
819 /* need valid S3 name (characters, length <= 1024, etc) */
820 rc = valid_fs_object_name(name);
821 if (rc != 0) {
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();
826 unref(rgw_fh);
827 get<0>(mkr) = nullptr;
828 get<1>(mkr) = rc;
829 return mkr;
830 }
831
832 string obj_name = std::string(name);
833 /* create an object representing the directory */
834 buffer::list bl;
835
836 /* XXXX */
837#if 0
838 bl.push_back(
839 buffer::create_static(len, static_cast<char*>(buffer)));
840#else
841
842 bl.push_back(
843 buffer::copy(link_path, strlen(link_path)));
844#endif
845
f67539c2
TL
846 RGWPutObjRequest req(get_context(), rgwlib.get_store()->get_user(user.user_id),
847 parent->bucket_name(), obj_name, bl);
11fdf7f2
TL
848
849 /* save attrs */
850 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
851 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
852
853 rc = rgwlib.get_fe()->execute_req(&req);
854 rc2 = req.get_ret();
855 if (! ((rc == 0) &&
856 (rc2 == 0))) {
857 /* op failed */
858 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
859 rgw_fh->mtx.unlock(); /* !LOCKED */
860 unref(rgw_fh);
861 get<0>(mkr) = nullptr;
862 /* fixup rc */
863 if (!rc)
864 rc = rc2;
865 } else {
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 */
870 }
871
872 get<1>(mkr) = rc;
873
874 return mkr;
875 } /* RGWLibFS::symlink */
876
7c673cae
FG
877 int RGWLibFS::getattr(RGWFileHandle* rgw_fh, struct stat* st)
878 {
879 switch(rgw_fh->fh.fh_type) {
880 case RGW_FS_TYPE_FILE:
881 {
882 if (rgw_fh->deleted())
883 return -ESTALE;
884 }
885 break;
886 default:
887 break;
888 };
494da23a 889 /* if rgw_fh is a directory, mtime will be advanced */
7c673cae
FG
890 return rgw_fh->stat(st);
891 } /* RGWLibFS::getattr */
892
893 int RGWLibFS::setattr(RGWFileHandle* rgw_fh, struct stat* st, uint32_t mask,
894 uint32_t flags)
895 {
896 int rc, rc2;
897 buffer::list ux_key, ux_attrs;
81eedcae
TL
898 buffer::list etag = rgw_fh->get_etag();
899 buffer::list acls = rgw_fh->get_acls();
7c673cae
FG
900
901 lock_guard guard(rgw_fh->mtx);
902
903 switch(rgw_fh->fh.fh_type) {
904 case RGW_FS_TYPE_FILE:
905 {
906 if (rgw_fh->deleted())
907 return -ESTALE;
908 }
909 break;
910 default:
911 break;
912 };
913
914 string obj_name{rgw_fh->relative_object_name()};
915
31f18b77
FG
916 if (rgw_fh->is_dir() &&
917 (likely(! rgw_fh->is_bucket()))) {
7c673cae
FG
918 obj_name += "/";
919 }
920
f67539c2
TL
921 RGWSetAttrsRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
922 rgw_fh->bucket_name(), obj_name);
7c673cae
FG
923
924 rgw_fh->create_stat(st, mask);
925 rgw_fh->encode_attrs(ux_key, ux_attrs);
926
927 /* save attrs */
928 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
929 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
81eedcae
TL
930 req.emplace_attr(RGW_ATTR_ETAG, std::move(etag));
931 req.emplace_attr(RGW_ATTR_ACL, std::move(acls));
7c673cae
FG
932
933 rc = rgwlib.get_fe()->execute_req(&req);
934 rc2 = req.get_ret();
935
936 if (rc == -ENOENT) {
937 /* special case: materialize placeholder dir */
938 buffer::list bl;
f67539c2 939 RGWPutObjRequest req(get_context(), rgwlib.get_store()->get_user(user.user_id), rgw_fh->bucket_name(),
7c673cae
FG
940 obj_name, bl);
941
942 rgw_fh->encode_attrs(ux_key, ux_attrs); /* because std::moved */
943
944 /* save attrs */
945 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
946 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
947
948 rc = rgwlib.get_fe()->execute_req(&req);
949 rc2 = req.get_ret();
950 }
951
952 if ((rc != 0) || (rc2 != 0)) {
953 return -EIO;
954 }
955
956 rgw_fh->set_ctime(real_clock::to_timespec(real_clock::now()));
957
958 return 0;
959 } /* RGWLibFS::setattr */
960
f67539c2
TL
961 static inline std::string prefix_xattr_keystr(const rgw_xattrstr& key) {
962 std::string keystr;
963 keystr.reserve(sizeof(RGW_ATTR_META_PREFIX) + key.len);
964 keystr += {RGW_ATTR_META_PREFIX};
965 keystr += string{key.val, key.len};
966 return keystr;
967 }
968
969 static inline std::string_view unprefix_xattr_keystr(const std::string& key)
970 {
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);
977 }
978 return svk;
979 }
980
981 int RGWLibFS::getxattrs(RGWFileHandle* rgw_fh, rgw_xattrlist *attrs,
982 rgw_getxattr_cb cb, void *cb_arg,
983 uint32_t flags)
984 {
985 /* cannot store on fs_root, should not on buckets? */
986 if ((rgw_fh->is_bucket()) ||
987 (rgw_fh->is_root())) {
988 return -EINVAL;
989 }
990
991 int rc, rc2, rc3;
992 string obj_name{rgw_fh->relative_object_name2()};
993
994 RGWGetAttrsRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
995 rgw_fh->bucket_name(), obj_name);
996
997 for (uint32_t ix = 0; ix < attrs->xattr_cnt; ++ix) {
998 auto& xattr = attrs->xattrs[ix];
999
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);
1004
1005 req.emplace_key(std::move(k));
1006 }
1007
1008 if (ldlog_p1(get_context(), ceph_subsys_rgw, 15)) {
1009 lsubdout(get_context(), rgw, 15)
1010 << __func__
1011 << " get keys for: "
1012 << rgw_fh->object_name()
1013 << " keys:"
1014 << dendl;
1015 for (const auto& attr: req.get_attrs()) {
1016 lsubdout(get_context(), rgw, 15)
1017 << "\tkey: " << attr.first << dendl;
1018 }
1019 }
1020
1021 rc = rgwlib.get_fe()->execute_req(&req);
1022 rc2 = req.get_ret();
1023 rc3 = ((rc == 0) && (rc2 == 0)) ? 0 : -EIO;
1024
1025 /* call back w/xattr data */
1026 if (rc3 == 0) {
1027 const auto& attrs = req.get_attrs();
1028 for (const auto& attr : attrs) {
1029
1030 if (!attr.second.has_value())
1031 continue;
1032
1033 const auto& k = attr.first;
1034 const auto& v = attr.second.value();
1035
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())})
1043 ? k
1044 : unprefix_xattr_keystr(k);
1045
1046 /* skip entries not matching prefix */
1047 if (svk.empty())
1048 continue;
1049
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 };
1057
1058 cb(&xattrlist, cb_arg, RGW_GETXATTR_FLAG_NONE);
1059 }
1060 }
1061
1062 return rc3;
1063 } /* RGWLibFS::getxattrs */
1064
1065 int RGWLibFS::lsxattrs(
1066 RGWFileHandle* rgw_fh, rgw_xattrstr *filter_prefix, rgw_getxattr_cb cb,
1067 void *cb_arg, uint32_t flags)
1068 {
1069 /* cannot store on fs_root, should not on buckets? */
1070 if ((rgw_fh->is_bucket()) ||
1071 (rgw_fh->is_root())) {
1072 return -EINVAL;
1073 }
1074
1075 int rc, rc2, rc3;
1076 string obj_name{rgw_fh->relative_object_name2()};
1077
1078 RGWGetAttrsRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
1079 rgw_fh->bucket_name(), obj_name);
1080
1081 rc = rgwlib.get_fe()->execute_req(&req);
1082 rc2 = req.get_ret();
1083 rc3 = ((rc == 0) && (rc2 == 0)) ? 0 : -EIO;
1084
1085 /* call back w/xattr data--check for eof */
1086 if (rc3 == 0) {
1087 const auto& keys = req.get_attrs();
1088 for (const auto& k : keys) {
1089
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())})
1094 ? k.first
1095 : unprefix_xattr_keystr(k.first);
1096
1097 /* skip entries not matching prefix */
1098 if (svk.empty())
1099 continue;
1100
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 };
1106
1107 auto cbr = cb(&xattrlist, cb_arg, RGW_LSXATTR_FLAG_NONE);
1108 if (cbr & RGW_LSXATTR_FLAG_STOP)
1109 break;
1110 }
1111 }
1112
1113 return rc3;
1114 } /* RGWLibFS::lsxattrs */
1115
1116 int RGWLibFS::setxattrs(RGWFileHandle* rgw_fh, rgw_xattrlist *attrs,
1117 uint32_t flags)
1118 {
1119 /* cannot store on fs_root, should not on buckets? */
1120 if ((rgw_fh->is_bucket()) ||
1121 (rgw_fh->is_root())) {
1122 return -EINVAL;
1123 }
1124
1125 int rc, rc2;
1126 string obj_name{rgw_fh->relative_object_name2()};
1127
1128 RGWSetAttrsRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
1129 rgw_fh->bucket_name(), obj_name);
1130
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))
1136 continue;
1137
1138 /* reject lexical match with any exposed attr */
1139 if (is_exposed_attr(xattr.key))
1140 continue;
1141
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));
1145 }
1146
1147 /* don't send null requests */
1148 if (! (req.get_attrs().size() > 0)) {
1149 return -EINVAL;
1150 }
1151
1152 rc = rgwlib.get_fe()->execute_req(&req);
1153 rc2 = req.get_ret();
1154
1155 return (((rc == 0) && (rc2 == 0)) ? 0 : -EIO);
1156
1157 } /* RGWLibFS::setxattrs */
1158
1159 int RGWLibFS::rmxattrs(RGWFileHandle* rgw_fh, rgw_xattrlist* attrs,
1160 uint32_t flags)
1161 {
1162 /* cannot store on fs_root, should not on buckets? */
1163 if ((rgw_fh->is_bucket()) ||
1164 (rgw_fh->is_root())) {
1165 return -EINVAL;
1166 }
1167
1168 int rc, rc2;
1169 string obj_name{rgw_fh->relative_object_name2()};
1170
1171 RGWRMAttrsRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
1172 rgw_fh->bucket_name(), obj_name);
1173
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)) {
1178 continue;
1179 }
1180 string k = prefix_xattr_keystr(xattr.key);
1181 req.emplace_key(std::move(k));
1182 }
1183
1184 /* don't send null requests */
1185 if (! (req.get_attrs().size() > 0)) {
1186 return -EINVAL;
1187 }
1188
1189 rc = rgwlib.get_fe()->execute_req(&req);
1190 rc2 = req.get_ret();
1191
1192 return (((rc == 0) && (rc2 == 0)) ? 0 : -EIO);
1193
1194 } /* RGWLibFS::rmxattrs */
1195
1196 /* called with rgw_fh->mtx held */
3efd9988 1197 void RGWLibFS::update_fh(RGWFileHandle *rgw_fh)
224ce89b
WB
1198 {
1199 int rc, rc2;
1200 string obj_name{rgw_fh->relative_object_name()};
1201 buffer::list ux_key, ux_attrs;
1202
1203 if (rgw_fh->is_dir() &&
1204 (likely(! rgw_fh->is_bucket()))) {
1205 obj_name += "/";
1206 }
1207
1208 lsubdout(get_context(), rgw, 17)
1209 << __func__
3efd9988 1210 << " update old versioned fh : " << obj_name
224ce89b
WB
1211 << dendl;
1212
f67539c2
TL
1213 RGWSetAttrsRequest req(cct, rgwlib.get_store()->get_user(user.user_id),
1214 rgw_fh->bucket_name(), obj_name);
224ce89b
WB
1215
1216 rgw_fh->encode_attrs(ux_key, ux_attrs);
1217
224ce89b 1218 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
3efd9988 1219 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
224ce89b
WB
1220
1221 rc = rgwlib.get_fe()->execute_req(&req);
1222 rc2 = req.get_ret();
1223
1224 if ((rc != 0) || (rc2 != 0)) {
1225 lsubdout(get_context(), rgw, 17)
1226 << __func__
3efd9988 1227 << " update fh failed : " << obj_name
224ce89b
WB
1228 << dendl;
1229 }
3efd9988 1230 } /* RGWLibFS::update_fh */
224ce89b 1231
7c673cae
FG
1232 void RGWLibFS::close()
1233 {
1234 state.flags |= FLAG_CLOSED;
1235
1236 class ObjUnref
1237 {
1238 RGWLibFS* fs;
1239 public:
11fdf7f2 1240 explicit ObjUnref(RGWLibFS* _fs) : fs(_fs) {}
7c673cae
FG
1241 void operator()(RGWFileHandle* fh) const {
1242 lsubdout(fs->get_context(), rgw, 5)
f67539c2 1243 << __PRETTY_FUNCTION__
7c673cae
FG
1244 << fh->name
1245 << " before ObjUnref refs=" << fh->get_refcnt()
1246 << dendl;
31f18b77 1247 fs->unref(fh);
7c673cae
FG
1248 }
1249 };
1250
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);
1255 rele();
1256 } /* RGWLibFS::close */
1257
494da23a
TL
1258 inline std::ostream& operator<<(std::ostream &os, fh_key const &fhk) {
1259 os << "<fh_key: bucket=";
1260 os << fhk.fh_hk.bucket;
1261 os << "; object=";
1262 os << fhk.fh_hk.object;
1263 os << ">";
1264 return os;
1265 }
1266
7c673cae
FG
1267 inline std::ostream& operator<<(std::ostream &os, struct timespec const &ts) {
1268 os << "<timespec: tv_sec=";
1269 os << ts.tv_sec;
1270 os << "; tv_nsec=";
1271 os << ts.tv_nsec;
1272 os << ">";
1273 return os;
1274 }
1275
1276 std::ostream& operator<<(std::ostream &os, RGWLibFS::event const &ev) {
1277 os << "<event:";
1278 switch (ev.t) {
1279 case RGWLibFS::event::type::READDIR:
1280 os << "type=READDIR;";
1281 break;
1282 default:
1283 os << "type=UNKNOWN;";
1284 break;
1285 };
1286 os << "fid=" << ev.fhk.fh_hk.bucket << ":" << ev.fhk.fh_hk.object
1287 << ";ts=" << ev.ts << ">";
1288 return os;
1289 }
1290
1291 void RGWLibFS::gc()
1292 {
1293 using std::get;
1294 using directory = RGWFileHandle::directory;
1295
1296 /* dirent invalidate timeout--basically, the upper-bound on
1297 * inconsistency with the S3 namespace */
1298 auto expire_s
1299 = get_context()->_conf->rgw_nfs_namespace_expire_secs;
1300
1301 /* max events to gc in one cycle */
c07f9fc5 1302 uint32_t max_ev = get_context()->_conf->rgw_nfs_max_gc;
7c673cae
FG
1303
1304 struct timespec now, expire_ts;
1305 event_vector ve;
1306 bool stop = false;
1307 std::deque<event> &events = state.events;
1308
1309 do {
1310 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
1311 lsubdout(get_context(), rgw, 15)
1312 << "GC: top of expire loop"
1313 << " now=" << now
1314 << " expire_s=" << expire_s
1315 << dendl;
1316 {
1317 lock_guard guard(state.mtx); /* LOCKED */
494da23a
TL
1318 lsubdout(get_context(), rgw, 15)
1319 << "GC: processing"
1320 << " count=" << events.size()
1321 << " events"
1322 << dendl;
1323 /* just return if no events */
7c673cae
FG
1324 if (events.empty()) {
1325 return;
1326 }
1327 uint32_t _max_ev =
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();
1331 expire_ts = ev.ts;
1332 expire_ts.tv_sec += expire_s;
1333 if (expire_ts > now) {
1334 stop = true;
1335 break;
1336 }
1337 ve.push_back(ev);
1338 events.pop_front();
1339 }
1340 } /* anon */
1341 /* !LOCKED */
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;
1349 if (rgw_fh) {
1350 RGWFileHandle::directory* d;
1351 if (unlikely(! rgw_fh->is_dir())) {
1352 lsubdout(get_context(), rgw, 0)
1353 << __func__
1354 << " BUG non-directory found with READDIR event "
1355 << "(" << rgw_fh->bucket_name() << ","
1356 << rgw_fh->object_name() << ")"
1357 << dendl;
1358 goto rele;
1359 }
1360 /* maybe clear state */
1361 d = get<directory>(&rgw_fh->variant_type);
1362 if (d) {
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
1373 << dendl;
1374 continue;
1375 } else {
1376 lsubdout(get_context(), rgw, 15)
1377 << "GC: expiring "
1378 << rgw_fh->object_name()
1379 << dendl;
1380 rgw_fh->clear_state();
1381 rgw_fh->invalidate();
1382 }
1383 }
1384 rele:
1385 unref(rgw_fh);
1386 } /* rgw_fh */
1387 } /* event::type::READDIR */
1388 } /* ev */
1389 ve.clear();
1390 } while (! (stop || shutdown));
1391 } /* RGWLibFS::gc */
1392
1393 std::ostream& operator<<(std::ostream &os,
1394 RGWFileHandle const &rgw_fh)
1395 {
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;";
1403 break;
1404 case RGW_FS_TYPE_FILE:
1405 os << "type=FILE;";
1406 break;
1407 default:
1408 os << "type=UNKNOWN;";
1409 break;
1410 };
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() << ";";
1414 os << ">";
1415 return os;
1416 }
1417
1418 RGWFileHandle::~RGWFileHandle() {
28e407b8
AA
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);
1423 }
7c673cae 1424 /* cond-unref parent */
3efd9988 1425 if (parent && (! parent->is_mount())) {
7c673cae
FG
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 */
31f18b77 1433 (void) get_fs()->unref(parent);
7c673cae
FG
1434 }
1435 }
1436
494da23a
TL
1437 fh_key RGWFileHandle::make_fhk(const std::string& name)
1438 {
1439 std::string tenant = get_fs()->get_user()->user_id.to_str();
1440 if (depth == 0) {
1441 /* S3 bucket -- assert mount-at-bucket case reaches here */
1442 return fh_key(name, name, tenant);
1443 } else {
1444 std::string key_name = make_key_name(name.c_str());
1445 return fh_key(fhk.fh_hk.bucket, key_name.c_str(), tenant);
1446 }
1447 }
1448
7c673cae
FG
1449 void RGWFileHandle::encode_attrs(ceph::buffer::list& ux_key1,
1450 ceph::buffer::list& ux_attrs1)
1451 {
11fdf7f2 1452 using ceph::encode;
7c673cae 1453 fh_key fhk(this->fh.fh_hk);
11fdf7f2
TL
1454 encode(fhk, ux_key1);
1455 encode(*this, ux_attrs1);
7c673cae
FG
1456 } /* RGWFileHandle::encode_attrs */
1457
3efd9988
FG
1458 DecodeAttrsResult RGWFileHandle::decode_attrs(const ceph::buffer::list* ux_key1,
1459 const ceph::buffer::list* ux_attrs1)
7c673cae 1460 {
11fdf7f2 1461 using ceph::decode;
3efd9988 1462 DecodeAttrsResult dar { false, false };
7c673cae 1463 fh_key fhk;
11fdf7f2
TL
1464 auto bl_iter_key1 = ux_key1->cbegin();
1465 decode(fhk, bl_iter_key1);
494da23a 1466 get<0>(dar) = true;
7c673cae 1467
11fdf7f2
TL
1468 auto bl_iter_unix1 = ux_attrs1->cbegin();
1469 decode(*this, bl_iter_unix1);
3efd9988
FG
1470 if (this->state.version < 2) {
1471 get<1>(dar) = true;
1472 }
224ce89b 1473
3efd9988 1474 return dar;
7c673cae
FG
1475 } /* RGWFileHandle::decode_attrs */
1476
f91f0fd5 1477 bool RGWFileHandle::reclaim(const cohort::lru::ObjectFactory* newobj_fac) {
7c673cae
FG
1478 lsubdout(fs->get_context(), rgw, 17)
1479 << __func__ << " " << *this
1480 << dendl;
f91f0fd5
TL
1481 auto factory = dynamic_cast<const RGWFileHandle::Factory*>(newobj_fac);
1482 if (factory == nullptr) {
1483 return false;
1484 }
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)) {
1488 return false;
1489 }
b32b8144 1490 /* in the non-delete case, handle may still be in handle table */
7c673cae 1491 if (fh_hook.is_linked()) {
b32b8144
FG
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);
7c673cae
FG
1495 }
1496 return true;
1497 } /* RGWFileHandle::reclaim */
1498
1499 bool RGWFileHandle::has_children() const
1500 {
1501 if (unlikely(! is_dir()))
1502 return false;
1503
f67539c2
TL
1504 RGWRMdirCheck req(fs->get_context(),
1505 rgwlib.get_store()->get_user(fs->get_user()->user_id),
1506 this);
7c673cae
FG
1507 int rc = rgwlib.get_fe()->execute_req(&req);
1508 if (! rc) {
1509 return req.valid && req.has_children;
1510 }
1511
1512 return false;
1513 }
1514
3efd9988
FG
1515 std::ostream& operator<<(std::ostream &os,
1516 RGWFileHandle::readdir_offset const &offset)
1517 {
1518 using boost::get;
1519 if (unlikely(!! get<uint64_t*>(&offset))) {
1520 uint64_t* ioff = get<uint64_t*>(offset);
1521 os << *ioff;
1522 }
1523 else
1524 os << get<const char*>(offset);
1525 return os;
1526 }
1527
1528 int RGWFileHandle::readdir(rgw_readdir_cb rcb, void *cb_arg,
1529 readdir_offset offset,
7c673cae
FG
1530 bool *eof, uint32_t flags)
1531 {
1532 using event = RGWLibFS::event;
3efd9988 1533 using boost::get;
7c673cae
FG
1534 int rc = 0;
1535 struct timespec now;
1536 CephContext* cct = fs->get_context();
1537
494da23a
TL
1538 lsubdout(cct, rgw, 10)
1539 << __func__ << " readdir called on "
1540 << object_name()
1541 << dendl;
1542
7c673cae
FG
1543 directory* d = get<directory>(&variant_type);
1544 if (d) {
1545 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
1546 lock_guard guard(mtx);
1547 d->last_readdir = now;
1548 }
1549
3efd9988 1550 bool initial_off;
494da23a
TL
1551 char* mk{nullptr};
1552
3efd9988 1553 if (likely(!! get<const char*>(&offset))) {
494da23a
TL
1554 mk = const_cast<char*>(get<const char*>(offset));
1555 initial_off = !mk;
3efd9988
FG
1556 } else {
1557 initial_off = (*get<uint64_t*>(offset) == 0);
1558 }
1559
7c673cae 1560 if (is_root()) {
f67539c2
TL
1561 RGWListBucketsRequest req(cct, rgwlib.get_store()->get_user(fs->get_user()->user_id),
1562 this, rcb, cb_arg, offset);
7c673cae
FG
1563 rc = rgwlib.get_fe()->execute_req(&req);
1564 if (! rc) {
1565 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
1566 lock_guard guard(mtx);
1567 state.atime = now;
3efd9988 1568 if (initial_off)
7c673cae
FG
1569 set_nlink(2);
1570 inc_nlink(req.d_count);
1571 *eof = req.eof();
7c673cae
FG
1572 }
1573 } else {
f67539c2
TL
1574 RGWReaddirRequest req(cct, rgwlib.get_store()->get_user(fs->get_user()->user_id),
1575 this, rcb, cb_arg, offset);
7c673cae
FG
1576 rc = rgwlib.get_fe()->execute_req(&req);
1577 if (! rc) {
1578 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
1579 lock_guard guard(mtx);
1580 state.atime = now;
3efd9988 1581 if (initial_off)
7c673cae
FG
1582 set_nlink(2);
1583 inc_nlink(req.d_count);
1584 *eof = req.eof();
7c673cae
FG
1585 }
1586 }
1587
494da23a
TL
1588 event ev(event::type::READDIR, get_key(), state.atime);
1589 lock_guard sguard(fs->state.mtx);
1590 fs->state.push_event(ev);
1591
7c673cae
FG
1592 lsubdout(fs->get_context(), rgw, 15)
1593 << __func__
1594 << " final link count=" << state.nlink
1595 << dendl;
1596
1597 return rc;
1598 } /* RGWFileHandle::readdir */
1599
1600 int RGWFileHandle::write(uint64_t off, size_t len, size_t *bytes_written,
1601 void *buffer)
1602 {
1603 using std::get;
1604 using WriteCompletion = RGWLibFS::WriteCompletion;
1605
1606 lock_guard guard(mtx);
1607
1608 int rc = 0;
1609
1610 file* f = get<file>(&variant_type);
1611 if (! f)
1612 return -EISDIR;
1613
1614 if (deleted()) {
1615 lsubdout(fs->get_context(), rgw, 5)
1616 << __func__
1617 << " write attempted on deleted object "
1618 << this->object_name()
1619 << dendl;
1620 /* zap write transaction, if any */
1621 if (f->write_req) {
1622 delete f->write_req;
1623 f->write_req = nullptr;
1624 }
1625 return -ESTALE;
1626 }
1627
1628 if (! f->write_req) {
1629 /* guard--we do not support (e.g., COW-backed) partial writes */
1630 if (off != 0) {
1631 lsubdout(fs->get_context(), rgw, 5)
1632 << __func__
1633 << " " << object_name()
1634 << " non-0 initial write position " << off
11fdf7f2 1635 << " (mounting with -o sync required)"
7c673cae
FG
1636 << dendl;
1637 return -EIO;
1638 }
1639
1640 /* start */
1641 std::string object_name = relative_object_name();
1642 f->write_req =
f67539c2
TL
1643 new RGWWriteRequest(rgwlib.get_store(),
1644 rgwlib.get_store()->get_user(fs->get_user()->user_id),
1645 this, bucket_name(), object_name);
7c673cae
FG
1646 rc = rgwlib.get_fe()->start_req(f->write_req);
1647 if (rc < 0) {
1648 lsubdout(fs->get_context(), rgw, 5)
1649 << __func__
1650 << this->object_name()
1651 << " write start failed " << off
1652 << " (" << rc << ")"
1653 << dendl;
1654 /* zap failed write transaction */
1655 delete f->write_req;
1656 f->write_req = nullptr;
1657 return -EIO;
1658 } else {
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));
1665 }
1666 }
1667 }
1668
3efd9988
FG
1669 int overlap = 0;
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;
1675 len -= overlap;
1676 }
1677
7c673cae
FG
1678 buffer::list bl;
1679 /* XXXX */
1680#if 0
1681 bl.push_back(
1682 buffer::create_static(len, static_cast<char*>(buffer)));
1683#else
1684 bl.push_back(
1685 buffer::copy(static_cast<char*>(buffer), len));
1686#endif
1687
1688 f->write_req->put_data(off, bl);
1689 rc = f->write_req->exec_continue();
1690
1691 if (rc == 0) {
1692 size_t min_size = off + len;
1693 if (min_size > get_size())
1694 set_size(min_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));
1699 }
1700 } else {
1701 /* continuation failed (e.g., non-contiguous write position) */
1702 lsubdout(fs->get_context(), rgw, 5)
1703 << __func__
1704 << object_name()
1705 << " failed write at position " << off
1706 << " (fails write transaction) "
1707 << dendl;
1708 /* zap failed write transaction */
1709 delete f->write_req;
1710 f->write_req = nullptr;
1711 rc = -EIO;
1712 }
1713
3efd9988 1714 *bytes_written = (rc == 0) ? (len + overlap) : 0;
7c673cae
FG
1715 return rc;
1716 } /* RGWFileHandle::write */
1717
1718 int RGWFileHandle::write_finish(uint32_t flags)
1719 {
1720 unique_lock guard{mtx, std::defer_lock};
1721 int rc = 0;
1722
1723 if (! (flags & FLAG_LOCKED)) {
1724 guard.lock();
1725 }
1726
1727 file* f = get<file>(&variant_type);
1728 if (f && (f->write_req)) {
1729 lsubdout(fs->get_context(), rgw, 10)
1730 << __func__
1731 << " finishing write trans on " << object_name()
1732 << dendl;
1733 rc = rgwlib.get_fe()->finish_req(f->write_req);
1734 if (! rc) {
1735 rc = f->write_req->get_ret();
1736 }
1737 delete f->write_req;
1738 f->write_req = nullptr;
1739 }
1740
1741 return rc;
1742 } /* RGWFileHandle::write_finish */
1743
1744 int RGWFileHandle::close()
1745 {
1746 lock_guard guard(mtx);
1747
1748 int rc = write_finish(FLAG_LOCKED);
1749
1750 flags &= ~FLAG_OPEN;
31f18b77
FG
1751 flags &= ~FLAG_STATELESS_OPEN;
1752
7c673cae
FG
1753 return rc;
1754 } /* RGWFileHandle::close */
1755
1756 RGWFileHandle::file::~file()
1757 {
1758 delete write_req;
1759 }
1760
1761 void RGWFileHandle::clear_state()
1762 {
1763 directory* d = get<directory>(&variant_type);
1764 if (d) {
1765 state.nlink = 2;
1766 d->last_marker = rgw_obj_key{};
1767 }
1768 }
1769
494da23a
TL
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))) {
1775 uniq.lock();
1776 }
1777
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;
1782 cmptime.tv_sec +=
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 */
1787 set_times(now);
1788 }
1789 }
1790
7c673cae
FG
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);
1795 }
1796 }
1797
1798 int RGWWriteRequest::exec_start() {
f67539c2
TL
1799 struct req_state* state = get_state();
1800
1801 /* Object needs a bucket from this point */
1802 state->object->set_bucket(state->bucket.get());
7c673cae 1803
224ce89b 1804 auto compression_type =
9f95a23c 1805 get_store()->svc()->zone->get_zone_params().get_compression_type(
f67539c2 1806 state->bucket->get_placement_rule());
224ce89b 1807
7c673cae 1808 /* not obviously supportable */
11fdf7f2
TL
1809 ceph_assert(! dlo_manifest);
1810 ceph_assert(! slo_info);
7c673cae
FG
1811
1812 perfcounter->inc(l_rgw_put);
1813 op_ret = -EINVAL;
1814
f67539c2
TL
1815 if (state->object->empty()) {
1816 ldout(state->cct, 0) << __func__ << " called on empty object" << dendl;
7c673cae
FG
1817 goto done;
1818 }
1819
f67539c2 1820 op_ret = get_params(null_yield);
7c673cae
FG
1821 if (op_ret < 0)
1822 goto done;
1823
f67539c2 1824 op_ret = get_system_versioning_params(state, &olh_epoch, &version_id);
7c673cae
FG
1825 if (op_ret < 0) {
1826 goto done;
1827 }
1828
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 */
11fdf7f2 1833
f67539c2 1834 aio.emplace(state->cct->_conf->rgw_put_obj_min_window_size);
11fdf7f2 1835
f67539c2 1836 if (state->bucket->versioning_enabled()) {
11fdf7f2 1837 if (!version_id.empty()) {
f67539c2 1838 state->object->set_instance(version_id);
11fdf7f2 1839 } else {
f67539c2
TL
1840 state->object->gen_rand_obj_instance_name();
1841 version_id = state->object->get_instance();
11fdf7f2
TL
1842 }
1843 }
f67539c2
TL
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 std::move(state->object->clone()), olh_epoch, state->req_id,
1849 this, state->yield);
11fdf7f2 1850
f67539c2 1851 op_ret = processor->prepare(state->yield);
224ce89b 1852 if (op_ret < 0) {
f67539c2 1853 ldout(state->cct, 20) << "processor->prepare() returned ret=" << op_ret
224ce89b
WB
1854 << dendl;
1855 goto done;
1856 }
11fdf7f2 1857 filter = &*processor;
224ce89b 1858 if (compression_type != "none") {
f67539c2 1859 plugin = Compressor::create(state->cct, compression_type);
11fdf7f2 1860 if (! plugin) {
f67539c2 1861 ldout(state->cct, 1) << "Cannot load plugin for rgw_compression_type "
11fdf7f2
TL
1862 << compression_type << dendl;
1863 } else {
f67539c2 1864 compressor.emplace(state->cct, plugin, filter);
11fdf7f2
TL
1865 filter = &*compressor;
1866 }
224ce89b 1867 }
7c673cae
FG
1868
1869 done:
1870 return op_ret;
1871 } /* exec_start */
1872
1873 int RGWWriteRequest::exec_continue()
1874 {
f67539c2 1875 struct req_state* state = get_state();
7c673cae
FG
1876 op_ret = 0;
1877
1878 /* check guards (e.g., contig write) */
11fdf7f2 1879 if (eio) {
f67539c2 1880 ldout(state->cct, 5)
11fdf7f2
TL
1881 << " chunks arrived in wrong order"
1882 << " (mounting with -o sync required)"
1883 << dendl;
1884 return -EIO;
1885 }
1886
f67539c2 1887 op_ret = state->bucket->check_quota(user_quota, bucket_quota, real_ofs, null_yield, true);
11fdf7f2
TL
1888 /* max_size exceed */
1889 if (op_ret < 0)
7c673cae
FG
1890 return -EIO;
1891
1892 size_t len = data.length();
1893 if (! len)
1894 return 0;
1895
11fdf7f2
TL
1896 hash.Update((const unsigned char *)data.c_str(), data.length());
1897 op_ret = filter->process(std::move(data), ofs);
7c673cae 1898 if (op_ret < 0) {
11fdf7f2 1899 goto done;
7c673cae
FG
1900 }
1901 bytes_written += len;
1902
1903 done:
1904 return op_ret;
1905 } /* exec_continue */
1906
1907 int RGWWriteRequest::exec_finish()
1908 {
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];
f67539c2 1913 struct req_state* state = get_state();
7c673cae
FG
1914
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();
1919
f67539c2
TL
1920 state->obj_size = bytes_written;
1921 perfcounter->inc(l_rgw_put_b, state->obj_size);
7c673cae 1922
11fdf7f2 1923 // flush data in filters
f67539c2 1924 op_ret = filter->process({}, state->obj_size);
11fdf7f2
TL
1925 if (op_ret < 0) {
1926 goto done;
1927 }
1928
f67539c2 1929 op_ret = state->bucket->check_quota(user_quota, bucket_quota, state->obj_size, null_yield, true);
11fdf7f2 1930 /* max_size exceed */
7c673cae
FG
1931 if (op_ret < 0) {
1932 goto done;
1933 }
1934
1935 hash.Final(m);
1936
224ce89b
WB
1937 if (compressor && compressor->is_compressed()) {
1938 bufferlist tmp;
1939 RGWCompressionInfo cs_info;
1940 cs_info.compression_type = plugin->get_type_name();
f67539c2 1941 cs_info.orig_size = state->obj_size;
224ce89b 1942 cs_info.blocks = std::move(compressor->get_compression_blocks());
11fdf7f2 1943 encode(cs_info, tmp);
224ce89b 1944 attrs[RGW_ATTR_COMPRESSION] = tmp;
b3b6e05e 1945 ldpp_dout(this, 20) << "storing " << RGW_ATTR_COMPRESSION
224ce89b
WB
1946 << " with type=" << cs_info.compression_type
1947 << ", orig_size=" << cs_info.orig_size
1948 << ", blocks=" << cs_info.blocks.size() << dendl;
1949 }
1950
7c673cae
FG
1951 buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5);
1952 etag = calc_md5;
1953
1954 bl.append(etag.c_str(), etag.size() + 1);
1955 emplace_attr(RGW_ATTR_ETAG, std::move(bl));
1956
1957 policy.encode(aclbl);
1958 emplace_attr(RGW_ATTR_ACL, std::move(aclbl));
1959
1960 /* unix attrs */
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);
1965
1966 emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
1967 emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
1968
f67539c2 1969 for (iter = state->generic_attrs.begin(); iter != state->generic_attrs.end();
7c673cae
FG
1970 ++iter) {
1971 buffer::list& attrbl = attrs[iter->first];
1972 const string& val = iter->second;
1973 attrbl.append(val.c_str(), val.size() + 1);
1974 }
1975
b3b6e05e 1976 op_ret = rgw_get_request_metadata(this, state->cct, state->info, attrs);
3efd9988
FG
1977 if (op_ret < 0) {
1978 goto done;
1979 }
7c673cae
FG
1980 encode_delete_at_attr(delete_at, attrs);
1981
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;
11fdf7f2
TL
1987 using ceph::encode;
1988 encode("True", slo_userindicator_bl);
7c673cae
FG
1989 emplace_attr(RGW_ATTR_SLO_UINDICATOR, std::move(slo_userindicator_bl));
1990 }
1991
f67539c2 1992 op_ret = processor->complete(state->obj_size, etag, &mtime, real_time(), attrs,
7c673cae 1993 (delete_at ? *delete_at : real_time()),
9f95a23c 1994 if_match, if_nomatch, nullptr, nullptr, nullptr,
f67539c2 1995 state->yield);
7c673cae
FG
1996 if (op_ret != 0) {
1997 /* revert attr updates */
1998 rgw_fh->set_mtime(omtime);
1999 rgw_fh->set_ctime(octime);
2000 rgw_fh->set_size(osize);
2001 }
2002
2003 done:
f67539c2 2004 perfcounter->tinc(l_rgw_put_lat, state->time_elapsed());
7c673cae
FG
2005 return op_ret;
2006 } /* exec_finish */
2007
2008} /* namespace rgw */
2009
2010/* librgw */
2011extern "C" {
2012
2013void rgwfile_version(int *major, int *minor, int *extra)
2014{
2015 if (major)
2016 *major = LIBRGW_FILE_VER_MAJOR;
2017 if (minor)
2018 *minor = LIBRGW_FILE_VER_MINOR;
2019 if (extra)
2020 *extra = LIBRGW_FILE_VER_EXTRA;
2021}
2022
2023/*
2024 attach rgw namespace
2025*/
2026 int rgw_mount(librgw_t rgw, const char *uid, const char *acc_key,
2027 const char *sec_key, struct rgw_fs **rgw_fs,
2028 uint32_t flags)
2029{
2030 int rc = 0;
2031
2032 /* stash access data for "mount" */
2033 RGWLibFS* new_fs = new RGWLibFS(static_cast<CephContext*>(rgw), uid, acc_key,
3efd9988 2034 sec_key, "/");
11fdf7f2 2035 ceph_assert(new_fs);
3efd9988 2036
b3b6e05e
TL
2037 const DoutPrefix dp(rgwlib.get_store()->ctx(), dout_subsys, "rgw mount: ");
2038 rc = new_fs->authorize(&dp, rgwlib.get_store());
3efd9988
FG
2039 if (rc != 0) {
2040 delete new_fs;
2041 return -EINVAL;
2042 }
2043
2044 /* register fs for shared gc */
2045 rgwlib.get_fe()->get_process()->register_fs(new_fs);
2046
2047 struct rgw_fs *fs = new_fs->get_fs();
2048 fs->rgw = rgw;
2049
2050 /* XXX we no longer assume "/" is unique, but we aren't tracking the
2051 * roots atm */
2052
2053 *rgw_fs = fs;
2054
2055 return 0;
2056}
2057
2058int 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,
2060 uint32_t flags)
2061{
2062 int rc = 0;
2063
2064 /* stash access data for "mount" */
2065 RGWLibFS* new_fs = new RGWLibFS(static_cast<CephContext*>(rgw), uid, acc_key,
2066 sec_key, root);
11fdf7f2 2067 ceph_assert(new_fs);
7c673cae 2068
b3b6e05e
TL
2069 const DoutPrefix dp(rgwlib.get_store()->ctx(), dout_subsys, "rgw mount2: ");
2070 rc = new_fs->authorize(&dp, rgwlib.get_store());
7c673cae
FG
2071 if (rc != 0) {
2072 delete new_fs;
2073 return -EINVAL;
2074 }
2075
2076 /* register fs for shared gc */
2077 rgwlib.get_fe()->get_process()->register_fs(new_fs);
2078
2079 struct rgw_fs *fs = new_fs->get_fs();
2080 fs->rgw = rgw;
2081
2082 /* XXX we no longer assume "/" is unique, but we aren't tracking the
2083 * roots atm */
2084
2085 *rgw_fs = fs;
2086
2087 return 0;
2088}
2089
2090/*
2091 register invalidate callbacks
2092*/
2093int rgw_register_invalidate(struct rgw_fs *rgw_fs, rgw_fh_callback_t cb,
2094 void *arg, uint32_t flags)
2095
2096{
2097 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2098 return fs->register_invalidate(cb, arg, flags);
2099}
2100
2101/*
2102 detach rgw namespace
2103*/
2104int rgw_umount(struct rgw_fs *rgw_fs, uint32_t flags)
2105{
2106 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2107 fs->close();
7c673cae
FG
2108 return 0;
2109}
2110
2111/*
2112 get filesystem attributes
2113*/
2114int rgw_statfs(struct rgw_fs *rgw_fs,
2115 struct rgw_file_handle *parent_fh,
2116 struct rgw_statvfs *vfs_st, uint32_t flags)
2117{
2118 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
28e407b8
AA
2119 struct rados_cluster_stat_t stats;
2120
f67539c2
TL
2121 RGWGetClusterStatReq req(fs->get_context(),
2122 rgwlib.get_store()->get_user(fs->get_user()->user_id),
2123 stats);
28e407b8
AA
2124 int rc = rgwlib.get_fe()->execute_req(&req);
2125 if (rc < 0) {
2126 lderr(fs->get_context()) << "ERROR: getting total cluster usage"
2127 << cpp_strerror(-rc) << dendl;
2128 return rc;
2129 }
7c673cae 2130
28e407b8
AA
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;
3efd9988
FG
2140 vfs_st->f_fsid[0] = fs->get_fsid();
2141 vfs_st->f_fsid[1] = fs->get_fsid();
7c673cae
FG
2142 vfs_st->f_flag = 0;
2143 vfs_st->f_namemax = 4096;
2144 return 0;
2145}
2146
2147/*
2148 generic create -- create an empty regular file
2149*/
2150int 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,
2153 uint32_t flags)
2154{
2155 using std::get;
2156
2157 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2158 RGWFileHandle* parent = get_rgwfh(parent_fh);
2159
2160 if ((! parent) ||
2161 (parent->is_root()) ||
2162 (parent->is_file())) {
2163 /* bad parent */
2164 return -EINVAL;
2165 }
2166
2167 MkObjResult fhr = fs->create(parent, name, st, mask, flags);
2168 RGWFileHandle *nfh = get<0>(fhr); // nullptr if !success
2169
2170 if (nfh)
2171 *fh = nfh->get_fh();
2172
2173 return get<1>(fhr);
2174} /* rgw_create */
2175
11fdf7f2
TL
2176/*
2177 create a symbolic link
2178 */
2179int 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,
2182 uint32_t flags)
2183{
2184 using std::get;
2185
2186 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2187 RGWFileHandle* parent = get_rgwfh(parent_fh);
2188
2189 if ((! parent) ||
2190 (parent->is_root()) ||
2191 (parent->is_file())) {
2192 /* bad parent */
2193 return -EINVAL;
2194 }
2195
2196 MkObjResult fhr = fs->symlink(parent, name, link_path, st, mask, flags);
2197 RGWFileHandle *nfh = get<0>(fhr); // nullptr if !success
2198
2199 if (nfh)
2200 *fh = nfh->get_fh();
2201
2202 return get<1>(fhr);
2203} /* rgw_symlink */
2204
7c673cae
FG
2205/*
2206 create a new directory
2207*/
2208int 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)
2212{
2213 using std::get;
2214
2215 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2216 RGWFileHandle* parent = get_rgwfh(parent_fh);
2217
2218 if (! parent) {
2219 /* bad parent */
2220 return -EINVAL;
2221 }
2222
2223 MkObjResult fhr = fs->mkdir(parent, name, st, mask, flags);
2224 RGWFileHandle *nfh = get<0>(fhr); // nullptr if !success
2225
2226 if (nfh)
2227 *fh = nfh->get_fh();
2228
2229 return get<1>(fhr);
2230} /* rgw_mkdir */
2231
2232/*
2233 rename object
2234*/
2235int 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,
2238 uint32_t flags)
2239{
2240 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2241
2242 RGWFileHandle* src_fh = get_rgwfh(src);
2243 RGWFileHandle* dst_fh = get_rgwfh(dst);
2244
2245 return fs->rename(src_fh, dst_fh, src_name, dst_name);
2246}
2247
2248/*
2249 remove file or directory
2250*/
2251int rgw_unlink(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh,
2252 const char *name, uint32_t flags)
2253{
2254 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2255 RGWFileHandle* parent = get_rgwfh(parent_fh);
2256
2257 return fs->unlink(parent, name);
2258}
2259
2260/*
2261 lookup object by name (POSIX style)
2262*/
2263int rgw_lookup(struct rgw_fs *rgw_fs,
2264 struct rgw_file_handle *parent_fh, const char* path,
eafe8130
TL
2265 struct rgw_file_handle **fh,
2266 struct stat *st, uint32_t mask, uint32_t flags)
7c673cae
FG
2267{
2268 //CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
2269 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2270
2271 RGWFileHandle* parent = get_rgwfh(parent_fh);
2272 if ((! parent) ||
2273 (! parent->is_dir())) {
2274 /* bad parent */
2275 return -EINVAL;
2276 }
2277
2278 RGWFileHandle* rgw_fh;
2279 LookupFHResult fhr;
2280
2281 if (parent->is_root()) {
2282 /* special: parent lookup--note lack of ref()! */
2283 if (unlikely((strcmp(path, "..") == 0) ||
2284 (strcmp(path, "/") == 0))) {
2285 rgw_fh = parent;
2286 } else {
31f18b77
FG
2287 RGWLibFS::BucketStats bstat;
2288 fhr = fs->stat_bucket(parent, path, bstat, RGWFileHandle::FLAG_NONE);
7c673cae
FG
2289 rgw_fh = get<0>(fhr);
2290 if (! rgw_fh)
2291 return -ENOENT;
2292 }
2293 } else {
224ce89b
WB
2294 /* special: after readdir--note extra ref()! */
2295 if (unlikely((strcmp(path, "..") == 0))) {
2296 rgw_fh = parent;
2297 lsubdout(fs->get_context(), rgw, 17)
11fdf7f2 2298 << __func__ << " BANG"<< *rgw_fh
224ce89b
WB
2299 << dendl;
2300 fs->ref(rgw_fh);
2301 } else {
224ce89b
WB
2302 enum rgw_fh_type fh_type = fh_type_of(flags);
2303
2304 uint32_t sl_flags = (flags & RGW_LOOKUP_FLAG_RCB)
f67539c2 2305 ? RGWFileHandle::FLAG_IN_CB
224ce89b
WB
2306 : RGWFileHandle::FLAG_EXACT_MATCH;
2307
eafe8130
TL
2308 bool fast_attrs= fs->get_context()->_conf->rgw_nfs_s3_fast_attrs;
2309
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);
2314 } else {
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);
2318 if (get<0>(fhr)) {
2319 rgw_fh = get<0>(fhr);
2320 goto done;
2321 }
2322 }
2323 fhr = fs->stat_leaf(parent, path, fh_type, sl_flags);
2324 }
224ce89b
WB
2325 if (! get<0>(fhr)) {
2326 if (! (flags & RGW_LOOKUP_FLAG_CREATE))
2327 return -ENOENT;
2328 else
2329 fhr = fs->lookup_fh(parent, path, RGWFileHandle::FLAG_CREATE);
2330 }
2331 rgw_fh = get<0>(fhr);
7c673cae 2332 }
7c673cae
FG
2333 } /* !root */
2334
eafe8130 2335done:
7c673cae
FG
2336 struct rgw_file_handle *rfh = rgw_fh->get_fh();
2337 *fh = rfh;
2338
2339 return 0;
2340} /* rgw_lookup */
2341
2342/*
2343 lookup object by handle (NFS style)
2344*/
2345int rgw_lookup_handle(struct rgw_fs *rgw_fs, struct rgw_fh_hk *fh_hk,
2346 struct rgw_file_handle **fh, uint32_t flags)
2347{
2348 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2349
2350 RGWFileHandle* rgw_fh = fs->lookup_handle(*fh_hk);
2351 if (! rgw_fh) {
2352 /* not found */
2353 return -ENOENT;
2354 }
2355
2356 struct rgw_file_handle *rfh = rgw_fh->get_fh();
2357 *fh = rfh;
2358
2359 return 0;
2360}
2361
2362/*
2363 * release file handle
2364 */
2365int rgw_fh_rele(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2366 uint32_t flags)
2367{
2368 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2369 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2370
2371 lsubdout(fs->get_context(), rgw, 17)
2372 << __func__ << " " << *rgw_fh
2373 << dendl;
2374
2375 fs->unref(rgw_fh);
2376 return 0;
2377}
2378
2379/*
2380 get unix attributes for object
2381*/
2382int rgw_getattr(struct rgw_fs *rgw_fs,
2383 struct rgw_file_handle *fh, struct stat *st, uint32_t flags)
2384{
2385 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2386 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2387
2388 return fs->getattr(rgw_fh, st);
2389}
2390
2391/*
2392 set unix attributes for object
2393*/
2394int rgw_setattr(struct rgw_fs *rgw_fs,
2395 struct rgw_file_handle *fh, struct stat *st,
2396 uint32_t mask, uint32_t flags)
2397{
2398 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2399 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2400
2401 return fs->setattr(rgw_fh, st, mask, flags);
2402}
2403
2404/*
2405 truncate file
2406*/
2407int rgw_truncate(struct rgw_fs *rgw_fs,
2408 struct rgw_file_handle *fh, uint64_t size, uint32_t flags)
2409{
2410 return 0;
2411}
2412
2413/*
2414 open file
2415*/
2416int rgw_open(struct rgw_fs *rgw_fs,
2417 struct rgw_file_handle *fh, uint32_t posix_flags, uint32_t flags)
2418{
2419 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2420
28e407b8 2421 /* XXX
7c673cae
FG
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
2425 *
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
2428 */
2429 if (! rgw_fh->is_file())
2430 return -EISDIR;
2431
2432 return rgw_fh->open(flags);
2433}
2434
2435/*
2436 close file
2437*/
2438int rgw_close(struct rgw_fs *rgw_fs,
2439 struct rgw_file_handle *fh, uint32_t flags)
2440{
2441 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2442 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2443 int rc = rgw_fh->close(/* XXX */);
2444
2445 if (flags & RGW_CLOSE_FLAG_RELE)
2446 fs->unref(rgw_fh);
2447
2448 return rc;
2449}
2450
2451int 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,
2454 uint32_t flags)
2455{
2456 RGWFileHandle* parent = get_rgwfh(parent_fh);
2457 if (! parent) {
2458 /* bad parent */
2459 return -EINVAL;
2460 }
3efd9988
FG
2461
2462 lsubdout(parent->get_fs()->get_context(), rgw, 15)
2463 << __func__
2464 << " offset=" << *offset
2465 << dendl;
2466
2467 if ((*offset == 0) &&
2468 (flags & RGW_READDIR_FLAG_DOTDOT)) {
2469 /* send '.' and '..' with their NFS-defined offsets */
eafe8130
TL
2470 rcb(".", cb_arg, 1, nullptr, 0, RGW_LOOKUP_FLAG_DIR);
2471 rcb("..", cb_arg, 2, nullptr, 0, RGW_LOOKUP_FLAG_DIR);
3efd9988
FG
2472 }
2473
7c673cae
FG
2474 int rc = parent->readdir(rcb, cb_arg, offset, eof, flags);
2475 return rc;
3efd9988
FG
2476} /* rgw_readdir */
2477
2478/* enumeration continuing from name */
2479int 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,
2482 uint32_t flags)
2483{
2484 RGWFileHandle* parent = get_rgwfh(parent_fh);
2485 if (! parent) {
2486 /* bad parent */
2487 return -EINVAL;
2488 }
2489
2490 lsubdout(parent->get_fs()->get_context(), rgw, 15)
2491 << __func__
94b18763 2492 << " offset=" << ((name) ? name : "(nil)")
3efd9988
FG
2493 << dendl;
2494
2495 if ((! name) &&
2496 (flags & RGW_READDIR_FLAG_DOTDOT)) {
2497 /* send '.' and '..' with their NFS-defined offsets */
eafe8130
TL
2498 rcb(".", cb_arg, 1, nullptr, 0, RGW_LOOKUP_FLAG_DIR);
2499 rcb("..", cb_arg, 2, nullptr, 0, RGW_LOOKUP_FLAG_DIR);
3efd9988
FG
2500 }
2501
2502 int rc = parent->readdir(rcb, cb_arg, name, eof, flags);
2503 return rc;
2504} /* rgw_readdir2 */
7c673cae 2505
c07f9fc5
FG
2506/* project offset of dirent name */
2507int rgw_dirent_offset(struct rgw_fs *rgw_fs,
2508 struct rgw_file_handle *parent_fh,
2509 const char *name, int64_t *offset,
2510 uint32_t flags)
2511{
2512 RGWFileHandle* parent = get_rgwfh(parent_fh);
2513 if ((! parent)) {
2514 /* bad parent */
2515 return -EINVAL;
2516 }
2517 std::string sname{name};
2518 int rc = parent->offset_of(sname, offset, flags);
2519 return rc;
2520}
2521
7c673cae
FG
2522/*
2523 read data from file
2524*/
2525int 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,
2528 uint32_t flags)
2529{
2530 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2531 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2532
2533 return fs->read(rgw_fh, offset, length, bytes_read, buffer, flags);
2534}
2535
11fdf7f2
TL
2536/*
2537 read symbolic link
2538*/
2539int 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,
2542 uint32_t flags)
2543{
2544 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2545 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2546
2547 return fs->readlink(rgw_fh, offset, length, bytes_read, buffer, flags);
2548}
2549
7c673cae
FG
2550/*
2551 write data to file
2552*/
2553int 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,
2556 uint32_t flags)
2557{
2558 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2559 int rc;
2560
2561 *bytes_written = 0;
2562
2563 if (! rgw_fh->is_file())
2564 return -EISDIR;
2565
3efd9988
FG
2566 if (! rgw_fh->is_open()) {
2567 if (flags & RGW_OPEN_FLAG_V3) {
2568 rc = rgw_fh->open(flags);
2569 if (!! rc)
2570 return rc;
2571 } else
2572 return -EPERM;
2573 }
7c673cae
FG
2574
2575 rc = rgw_fh->write(offset, length, bytes_written, buffer);
2576
2577 return rc;
2578}
2579
2580/*
2581 read data from file (vector)
2582*/
2583class RGWReadV
2584{
2585 buffer::list bl;
2586 struct rgw_vio* vio;
2587
2588public:
2589 RGWReadV(buffer::list& _bl, rgw_vio* _vio) : vio(_vio) {
f67539c2 2590 bl = std::move(_bl);
7c673cae
FG
2591 }
2592
2593 struct rgw_vio* get_vio() { return vio; }
2594
11fdf7f2 2595 const auto& buffers() { return bl.buffers(); }
7c673cae
FG
2596
2597 unsigned /* XXX */ length() { return bl.length(); }
2598
2599};
2600
2601void rgw_readv_rele(struct rgw_uio *uio, uint32_t flags)
2602{
2603 RGWReadV* rdv = static_cast<RGWReadV*>(uio->uio_p1);
2604 rdv->~RGWReadV();
2605 ::operator delete(rdv);
2606}
2607
2608int rgw_readv(struct rgw_fs *rgw_fs,
2609 struct rgw_file_handle *fh, rgw_uio *uio, uint32_t flags)
2610{
2611#if 0 /* XXX */
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);
2615
2616 if (! rgw_fh->is_file())
2617 return -EINVAL;
2618
2619 int rc = 0;
2620
2621 buffer::list bl;
2622 RGWGetObjRequest req(cct, fs->get_user(), rgw_fh->bucket_name(),
2623 rgw_fh->object_name(), uio->uio_offset, uio->uio_resid,
2624 bl);
2625 req.do_hexdump = false;
2626
2627 rc = rgwlib.get_fe()->execute_req(&req);
2628
2629 if (! rc) {
2630 RGWReadV* rdv = static_cast<RGWReadV*>(
2631 ::operator new(sizeof(RGWReadV) +
2632 (bl.buffers().size() * sizeof(struct rgw_vio))));
2633
2634 (void) new (rdv)
2635 RGWReadV(bl, reinterpret_cast<rgw_vio*>(rdv+sizeof(RGWReadV)));
2636
2637 uio->uio_p1 = rdv;
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;
2642
2643 int ix = 0;
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;
2651 ++ix;
2652 }
2653 }
2654
2655 return rc;
2656#else
2657 return 0;
2658#endif
2659}
2660
2661/*
2662 write data to file (vector)
2663*/
2664int rgw_writev(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2665 rgw_uio *uio, uint32_t flags)
2666{
2667
f67539c2 2668 // not supported - rest of function is ignored
7c673cae
FG
2669 return -ENOTSUP;
2670
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);
2674
2675 if (! rgw_fh->is_file())
2676 return -EINVAL;
2677
2678 buffer::list bl;
2679 for (unsigned int ix = 0; ix < uio->uio_cnt; ++ix) {
2680 rgw_vio *vio = &(uio->uio_vio[ix]);
2681 bl.push_back(
2682 buffer::create_static(vio->vio_len,
2683 static_cast<char*>(vio->vio_base)));
2684 }
2685
2686 std::string oname = rgw_fh->relative_object_name();
f67539c2
TL
2687 RGWPutObjRequest req(cct, rgwlib.get_store()->get_user(fs->get_user()->user_id),
2688 rgw_fh->bucket_name(), oname, bl);
7c673cae
FG
2689
2690 int rc = rgwlib.get_fe()->execute_req(&req);
2691
2692 /* XXX update size (in request) */
2693
2694 return rc;
2695}
2696
2697/*
2698 sync written data
2699*/
2700int rgw_fsync(struct rgw_fs *rgw_fs, struct rgw_file_handle *handle,
2701 uint32_t flags)
2702{
2703 return 0;
2704}
2705
2706int rgw_commit(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2707 uint64_t offset, uint64_t length, uint32_t flags)
2708{
2709 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2710
2711 return rgw_fh->commit(offset, length, RGWFileHandle::FLAG_NONE);
2712}
2713
f67539c2
TL
2714/*
2715 extended attributes
2716 */
2717
2718int rgw_getxattrs(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2719 rgw_xattrlist *attrs, rgw_getxattr_cb cb, void *cb_arg,
2720 uint32_t flags)
2721{
2722 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2723 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2724
2725 return fs->getxattrs(rgw_fh, attrs, cb, cb_arg, flags);
2726}
2727
2728int 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)
2731{
2732 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2733 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2734
2735 return fs->lsxattrs(rgw_fh, filter_prefix, cb, cb_arg, flags);
2736}
2737
2738int rgw_setxattrs(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2739 rgw_xattrlist *attrs, uint32_t flags)
2740{
2741 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2742 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2743
2744 return fs->setxattrs(rgw_fh, attrs, flags);
2745}
2746
2747int rgw_rmxattrs(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2748 rgw_xattrlist *attrs, uint32_t flags)
2749{
2750 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2751 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2752
2753 return fs->rmxattrs(rgw_fh, attrs, flags);
2754}
2755
7c673cae 2756} /* extern "C" */