]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_file.cc
update sources to v12.2.3
[ceph.git] / ceph / src / rgw / rgw_file.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
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"
11#include "rgw_rados.h"
12#include "rgw_resolve.h"
13#include "rgw_op.h"
14#include "rgw_rest.h"
15#include "rgw_acl.h"
16#include "rgw_acl_s3.h"
17#include "rgw_frontend.h"
18#include "rgw_request.h"
19#include "rgw_process.h"
20#include "rgw_rest_user.h"
21#include "rgw_rest_s3.h"
22#include "rgw_os_lib.h"
23#include "rgw_auth_s3.h"
24#include "rgw_user.h"
25#include "rgw_bucket.h"
26
27#include "rgw_file.h"
28#include "rgw_lib_frontend.h"
29
30#include <atomic>
31
32#define dout_subsys ceph_subsys_rgw
33
34using namespace rgw;
35
36namespace rgw {
37
38 extern RGWLib rgwlib;
39
40 const string RGWFileHandle::root_name = "/";
41
42 std::atomic<uint32_t> RGWLibFS::fs_inst_counter;
43
44 uint32_t RGWLibFS::write_completion_interval_s = 10;
45
46 ceph::timer<ceph::mono_clock> RGWLibFS::write_timer{
47 ceph::construct_suspended};
48
49 inline int valid_fs_bucket_name(const string& name) {
50 int rc = valid_s3_bucket_name(name, false /* relaxed */);
51 if (rc != 0) {
52 if (name.size() > 255)
53 return -ENAMETOOLONG;
54 return -EINVAL;
55 }
56 return 0;
57 }
58
59 inline int valid_fs_object_name(const string& name) {
60 int rc = valid_s3_object_name(name);
61 if (rc != 0) {
62 if (name.size() > 1024)
63 return -ENAMETOOLONG;
64 return -EINVAL;
65 }
66 return 0;
67 }
68
31f18b77
FG
69 LookupFHResult RGWLibFS::stat_bucket(RGWFileHandle* parent, const char *path,
70 RGWLibFS::BucketStats& bs,
71 uint32_t flags)
7c673cae
FG
72 {
73 LookupFHResult fhr{nullptr, 0};
74 std::string bucket_name{path};
31f18b77 75 RGWStatBucketRequest req(cct, get_user(), bucket_name, bs);
7c673cae
FG
76
77 int rc = rgwlib.get_fe()->execute_req(&req);
78 if ((rc == 0) &&
79 (req.get_ret() == 0) &&
80 (req.matched())) {
81 fhr = lookup_fh(parent, path,
31f18b77 82 (flags & RGWFileHandle::FLAG_LOCKED)|
7c673cae
FG
83 RGWFileHandle::FLAG_CREATE|
84 RGWFileHandle::FLAG_BUCKET);
85 if (get<0>(fhr)) {
86 RGWFileHandle* rgw_fh = get<0>(fhr);
31f18b77
FG
87 if (! (flags & RGWFileHandle::FLAG_LOCKED)) {
88 rgw_fh->mtx.lock();
89 }
7c673cae
FG
90 rgw_fh->set_times(req.get_ctime());
91 /* restore attributes */
92 auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
93 auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
94 if (ux_key && ux_attrs) {
3efd9988
FG
95 DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
96 if (get<0>(dar) || get<1>(dar)) {
97 update_fh(rgw_fh);
98 }
7c673cae 99 }
31f18b77
FG
100 if (! (flags & RGWFileHandle::FLAG_LOCKED)) {
101 rgw_fh->mtx.unlock();
102 }
7c673cae
FG
103 }
104 }
105 return fhr;
106 }
107
108 LookupFHResult RGWLibFS::stat_leaf(RGWFileHandle* parent,
109 const char *path,
110 enum rgw_fh_type type,
111 uint32_t flags)
112 {
113 /* find either-of <object_name>, <object_name/>, only one of
114 * which should exist; atomicity? */
115 using std::get;
116
117 LookupFHResult fhr{nullptr, 0};
118
119 /* XXX the need for two round-trip operations to identify file or
120 * directory leaf objects is unecessary--the current proposed
121 * mechanism to avoid this is to store leaf object names with an
122 * object locator w/o trailing slash */
123
31f18b77 124 std::string obj_path = parent->format_child_name(path, false);
7c673cae
FG
125
126 for (auto ix : { 0, 1, 2 }) {
127 switch (ix) {
128 case 0:
129 {
130 /* type hint */
131 if (type == RGW_FS_TYPE_DIRECTORY)
132 continue;
133
134 RGWStatObjRequest req(cct, get_user(),
135 parent->bucket_name(), obj_path,
136 RGWStatObjRequest::FLAG_NONE);
137 int rc = rgwlib.get_fe()->execute_req(&req);
138 if ((rc == 0) &&
139 (req.get_ret() == 0)) {
140 fhr = lookup_fh(parent, path, RGWFileHandle::FLAG_CREATE);
141 if (get<0>(fhr)) {
142 RGWFileHandle* rgw_fh = get<0>(fhr);
143 lock_guard guard(rgw_fh->mtx);
144 rgw_fh->set_size(req.get_size());
145 rgw_fh->set_times(req.get_mtime());
146 /* restore attributes */
147 auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
148 auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
149 if (ux_key && ux_attrs) {
3efd9988
FG
150 DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
151 if (get<0>(dar) || get<1>(dar)) {
152 update_fh(rgw_fh);
153 }
7c673cae
FG
154 }
155 }
156 goto done;
157 }
158 }
159 break;
160 case 1:
161 {
162 /* try dir form */
163 /* type hint */
164 if (type == RGW_FS_TYPE_FILE)
165 continue;
166
167 obj_path += "/";
168 RGWStatObjRequest req(cct, get_user(),
169 parent->bucket_name(), obj_path,
170 RGWStatObjRequest::FLAG_NONE);
171 int rc = rgwlib.get_fe()->execute_req(&req);
172 if ((rc == 0) &&
173 (req.get_ret() == 0)) {
174 fhr = lookup_fh(parent, path, RGWFileHandle::FLAG_DIRECTORY);
175 if (get<0>(fhr)) {
176 RGWFileHandle* rgw_fh = get<0>(fhr);
177 lock_guard guard(rgw_fh->mtx);
178 rgw_fh->set_size(req.get_size());
179 rgw_fh->set_times(req.get_mtime());
180 /* restore attributes */
181 auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
182 auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
183 if (ux_key && ux_attrs) {
3efd9988
FG
184 DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
185 if (get<0>(dar) || get<1>(dar)) {
186 update_fh(rgw_fh);
187 }
7c673cae
FG
188 }
189 }
190 goto done;
191 }
192 }
193 break;
194 case 2:
195 {
196 std::string object_name{path};
197 RGWStatLeafRequest req(cct, get_user(), parent, object_name);
198 int rc = rgwlib.get_fe()->execute_req(&req);
199 if ((rc == 0) &&
200 (req.get_ret() == 0)) {
201 if (req.matched) {
202 /* we need rgw object's key name equal to file name, if
203 * not return NULL */
204 if ((flags & RGWFileHandle::FLAG_EXACT_MATCH) &&
205 !req.exact_matched) {
206 lsubdout(get_context(), rgw, 15)
207 << __func__
208 << ": stat leaf not exact match file name = "
209 << path << dendl;
210 goto done;
211 }
212 fhr = lookup_fh(parent, path,
213 RGWFileHandle::FLAG_CREATE|
214 ((req.is_dir) ?
215 RGWFileHandle::FLAG_DIRECTORY :
216 RGWFileHandle::FLAG_NONE));
217 /* XXX we don't have an object--in general, there need not
218 * be one (just a path segment in some other object). In
219 * actual leaf an object exists, but we'd need another round
220 * trip to get attrs */
221 if (get<0>(fhr)) {
222 /* for now use the parent object's mtime */
223 RGWFileHandle* rgw_fh = get<0>(fhr);
224 lock_guard guard(rgw_fh->mtx);
225 rgw_fh->set_mtime(parent->get_mtime());
226 }
227 }
228 }
229 }
230 break;
231 default:
232 /* not reached */
233 break;
234 }
235 }
236 done:
237 return fhr;
238 } /* RGWLibFS::stat_leaf */
239
240 int RGWLibFS::read(RGWFileHandle* rgw_fh, uint64_t offset, size_t length,
241 size_t* bytes_read, void* buffer, uint32_t flags)
242 {
243 if (! rgw_fh->is_file())
244 return -EINVAL;
245
246 if (rgw_fh->deleted())
247 return -ESTALE;
248
249 RGWReadRequest req(get_context(), get_user(), rgw_fh, offset, length,
250 buffer);
251
252 int rc = rgwlib.get_fe()->execute_req(&req);
253 if ((rc == 0) &&
254 (req.get_ret() == 0)) {
255 lock_guard(rgw_fh->mtx);
256 rgw_fh->set_atime(real_clock::to_timespec(real_clock::now()));
257 *bytes_read = req.nread;
258 }
259
260 return rc;
261 }
262
263 int RGWLibFS::unlink(RGWFileHandle* rgw_fh, const char* name, uint32_t flags)
264 {
265 int rc = 0;
31f18b77 266 BucketStats bs;
7c673cae 267 RGWFileHandle* parent = nullptr;
31f18b77 268 RGWFileHandle* bkt_fh = nullptr;
7c673cae
FG
269
270 if (unlikely(flags & RGWFileHandle::FLAG_UNLINK_THIS)) {
271 /* LOCKED */
272 parent = rgw_fh->get_parent();
273 } else {
274 /* atomicity */
275 parent = rgw_fh;
276 LookupFHResult fhr = lookup_fh(parent, name, RGWFileHandle::FLAG_LOCK);
277 rgw_fh = get<0>(fhr);
278 /* LOCKED */
279 }
280
281 if (parent->is_root()) {
31f18b77
FG
282 /* a bucket may have an object storing Unix attributes, check
283 * for and delete it */
284 LookupFHResult fhr;
285 fhr = stat_bucket(parent, name, bs, (rgw_fh) ?
286 RGWFileHandle::FLAG_LOCKED :
287 RGWFileHandle::FLAG_NONE);
288 bkt_fh = get<0>(fhr);
289 if (unlikely(! bkt_fh)) {
290 /* implies !rgw_fh, so also !LOCKED */
291 return -ENOENT;
292 }
293
294 if (bs.num_entries > 1) {
295 unref(bkt_fh); /* return stat_bucket ref */
296 if (likely(!! rgw_fh)) { /* return lock and ref from
297 * lookup_fh (or caller in the
298 * special case of
299 * RGWFileHandle::FLAG_UNLINK_THIS) */
300 rgw_fh->mtx.unlock();
301 unref(rgw_fh);
302 }
303 return -ENOTEMPTY;
304 } else {
305 /* delete object w/key "<bucket>/" (uxattrs), if any */
306 string oname{"/"};
307 RGWDeleteObjRequest req(cct, get_user(), bkt_fh->bucket_name(), oname);
308 rc = rgwlib.get_fe()->execute_req(&req);
309 /* don't care if ENOENT */
310 unref(bkt_fh);
311 }
312
313 string bname{name};
314 RGWDeleteBucketRequest req(cct, get_user(), bname);
7c673cae
FG
315 rc = rgwlib.get_fe()->execute_req(&req);
316 if (! rc) {
317 rc = req.get_ret();
318 }
319 } else {
320 /*
321 * leaf object
322 */
323 if (! rgw_fh) {
324 /* XXX for now, peform a hard lookup to deduce the type of
325 * object to be deleted ("foo" vs. "foo/")--also, ensures
326 * atomicity at this endpoint */
327 struct rgw_file_handle *fh;
328 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &fh,
329 RGW_LOOKUP_FLAG_NONE);
330 if (!! rc)
331 return rc;
332
333 /* rgw_fh ref+ */
334 rgw_fh = get_rgwfh(fh);
335 rgw_fh->mtx.lock(); /* LOCKED */
336 }
337
338 std::string oname = rgw_fh->relative_object_name();
339 if (rgw_fh->is_dir()) {
340 /* for the duration of our cache timer, trust positive
341 * child cache */
342 if (rgw_fh->has_children()) {
343 rgw_fh->mtx.unlock();
344 unref(rgw_fh);
345 return(-ENOTEMPTY);
346 }
347 oname += "/";
348 }
349 RGWDeleteObjRequest req(cct, get_user(), parent->bucket_name(),
350 oname);
351 rc = rgwlib.get_fe()->execute_req(&req);
352 if (! rc) {
353 rc = req.get_ret();
354 }
355 }
356
31f18b77
FG
357 /* ENOENT when raced with other s3 gateway */
358 if (! rc || rc == -ENOENT) {
359 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
360 fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh,
361 RGWFileHandle::FHCache::FLAG_LOCK);
362 }
7c673cae
FG
363
364 if (! rc) {
365 real_time t = real_clock::now();
366 parent->set_mtime(real_clock::to_timespec(t));
367 parent->set_ctime(real_clock::to_timespec(t));
368 }
369
370 rgw_fh->mtx.unlock();
371 unref(rgw_fh);
372
373 return rc;
374 } /* RGWLibFS::unlink */
375
376 int RGWLibFS::rename(RGWFileHandle* src_fh, RGWFileHandle* dst_fh,
377 const char *_src_name, const char *_dst_name)
378
379 {
380 /* XXX initial implementation: try-copy, and delete if copy
381 * succeeds */
382 int rc = -EINVAL;
383
384 real_time t;
385
386 std::string src_name{_src_name};
387 std::string dst_name{_dst_name};
388
389 /* atomicity */
390 LookupFHResult fhr = lookup_fh(src_fh, _src_name, RGWFileHandle::FLAG_LOCK);
391 RGWFileHandle* rgw_fh = get<0>(fhr);
392
393 /* should not happen */
394 if (! rgw_fh) {
395 ldout(get_context(), 0) << __func__
396 << " BUG no such src renaming path="
397 << src_name
398 << dendl;
399 goto out;
400 }
401
402 /* forbid renaming of directories (unreasonable at scale) */
403 if (rgw_fh->is_dir()) {
404 ldout(get_context(), 12) << __func__
405 << " rejecting attempt to rename directory path="
406 << rgw_fh->full_object_name()
407 << dendl;
408 rc = -EPERM;
409 goto unlock;
410 }
411
412 /* forbid renaming open files (violates intent, for now) */
413 if (rgw_fh->is_open()) {
414 ldout(get_context(), 12) << __func__
415 << " rejecting attempt to rename open file path="
416 << rgw_fh->full_object_name()
417 << dendl;
418 rc = -EPERM;
419 goto unlock;
420 }
421
422 t = real_clock::now();
423
424 for (int ix : {0, 1}) {
425 switch (ix) {
426 case 0:
427 {
428 RGWCopyObjRequest req(cct, get_user(), src_fh, dst_fh, src_name,
429 dst_name);
430 int rc = rgwlib.get_fe()->execute_req(&req);
431 if ((rc != 0) ||
432 ((rc = req.get_ret()) != 0)) {
433 ldout(get_context(), 1)
434 << __func__
435 << " rename step 0 failed src="
436 << src_fh->full_object_name() << " " << src_name
437 << " dst=" << dst_fh->full_object_name()
438 << " " << dst_name
439 << "rc " << rc
440 << dendl;
441 goto unlock;
442 }
443 ldout(get_context(), 12)
444 << __func__
445 << " rename step 0 success src="
446 << src_fh->full_object_name() << " " << src_name
447 << " dst=" << dst_fh->full_object_name()
448 << " " << dst_name
449 << " rc " << rc
450 << dendl;
451 /* update dst change id */
452 dst_fh->set_times(t);
453 }
454 break;
455 case 1:
456 {
457 rc = this->unlink(rgw_fh /* LOCKED */, _src_name,
458 RGWFileHandle::FLAG_UNLINK_THIS);
459 /* !LOCKED, -ref */
460 if (! rc) {
461 ldout(get_context(), 12)
462 << __func__
463 << " rename step 1 success src="
464 << src_fh->full_object_name() << " " << src_name
465 << " dst=" << dst_fh->full_object_name()
466 << " " << dst_name
467 << " rc " << rc
468 << dendl;
469 /* update src change id */
470 src_fh->set_times(t);
471 } else {
472 ldout(get_context(), 1)
473 << __func__
474 << " rename step 1 failed src="
475 << src_fh->full_object_name() << " " << src_name
476 << " dst=" << dst_fh->full_object_name()
477 << " " << dst_name
478 << " rc " << rc
479 << dendl;
480 }
481 }
482 goto out;
483 default:
484 abort();
485 } /* switch */
486 } /* ix */
487 unlock:
488 rgw_fh->mtx.unlock(); /* !LOCKED */
489 unref(rgw_fh); /* -ref */
490
491 out:
492 return rc;
493 } /* RGWLibFS::rename */
494
495 MkObjResult RGWLibFS::mkdir(RGWFileHandle* parent, const char *name,
496 struct stat *st, uint32_t mask, uint32_t flags)
497 {
7c673cae 498 int rc, rc2;
31f18b77
FG
499 rgw_file_handle *lfh;
500
501 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh,
502 RGW_LOOKUP_FLAG_NONE);
503 if (! rc) {
504 /* conflict! */
505 rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE);
506 return MkObjResult{nullptr, -EEXIST};
507 }
7c673cae 508
31f18b77 509 MkObjResult mkr{nullptr, -EINVAL};
7c673cae
FG
510 LookupFHResult fhr;
511 RGWFileHandle* rgw_fh = nullptr;
512 buffer::list ux_key, ux_attrs;
513
514 fhr = lookup_fh(parent, name,
515 RGWFileHandle::FLAG_CREATE|
516 RGWFileHandle::FLAG_DIRECTORY|
517 RGWFileHandle::FLAG_LOCK);
518 rgw_fh = get<0>(fhr);
519 if (rgw_fh) {
520 rgw_fh->create_stat(st, mask);
521 rgw_fh->set_times(real_clock::now());
522 /* save attrs */
523 rgw_fh->encode_attrs(ux_key, ux_attrs);
524 if (st)
525 rgw_fh->stat(st);
526 get<0>(mkr) = rgw_fh;
527 } else {
528 get<1>(mkr) = -EIO;
529 return mkr;
530 }
531
532 if (parent->is_root()) {
533 /* bucket */
534 string bname{name};
535 /* enforce S3 name restrictions */
536 rc = valid_fs_bucket_name(bname);
537 if (rc != 0) {
538 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
539 fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh,
540 RGWFileHandle::FHCache::FLAG_LOCK);
541 rgw_fh->mtx.unlock();
542 unref(rgw_fh);
543 get<0>(mkr) = nullptr;
544 get<1>(mkr) = rc;
545 return mkr;
546 }
547
31f18b77 548 RGWCreateBucketRequest req(get_context(), get_user(), bname);
7c673cae
FG
549
550 /* save attrs */
551 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
552 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
553
554 rc = rgwlib.get_fe()->execute_req(&req);
555 rc2 = req.get_ret();
556 } else {
557 /* create an object representing the directory */
558 buffer::list bl;
31f18b77 559 string dir_name = parent->format_child_name(name, true);
7c673cae
FG
560
561 /* need valid S3 name (characters, length <= 1024, etc) */
562 rc = valid_fs_object_name(dir_name);
563 if (rc != 0) {
564 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
565 fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh,
566 RGWFileHandle::FHCache::FLAG_LOCK);
567 rgw_fh->mtx.unlock();
568 unref(rgw_fh);
569 get<0>(mkr) = nullptr;
570 get<1>(mkr) = rc;
571 return mkr;
572 }
573
574 RGWPutObjRequest req(get_context(), get_user(), parent->bucket_name(),
575 dir_name, bl);
576
577 /* save attrs */
578 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
579 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
580
581 rc = rgwlib.get_fe()->execute_req(&req);
582 rc2 = req.get_ret();
583 }
584
585 if (! ((rc == 0) &&
586 (rc2 == 0))) {
587 /* op failed */
588 rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
589 rgw_fh->mtx.unlock(); /* !LOCKED */
590 unref(rgw_fh);
591 get<0>(mkr) = nullptr;
592 /* fixup rc */
593 if (!rc)
594 rc = rc2;
595 } else {
596 real_time t = real_clock::now();
597 parent->set_mtime(real_clock::to_timespec(t));
598 parent->set_ctime(real_clock::to_timespec(t));
599 rgw_fh->mtx.unlock(); /* !LOCKED */
600 }
601
602 get<1>(mkr) = rc;
603
604 return mkr;
605 } /* RGWLibFS::mkdir */
606
607 MkObjResult RGWLibFS::create(RGWFileHandle* parent, const char *name,
608 struct stat *st, uint32_t mask, uint32_t flags)
609 {
610 int rc, rc2;
611
612 using std::get;
613
614 rgw_file_handle *lfh;
615 rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh,
616 RGW_LOOKUP_FLAG_NONE);
617 if (! rc) {
618 /* conflict! */
619 rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE);
620 return MkObjResult{nullptr, -EEXIST};
621 }
622
623 /* expand and check name */
31f18b77 624 std::string obj_name = parent->format_child_name(name, false);
7c673cae
FG
625 rc = valid_fs_object_name(obj_name);
626 if (rc != 0) {
627 return MkObjResult{nullptr, rc};
628 }
629
630 /* create it */
631 buffer::list bl;
632 RGWPutObjRequest req(cct, get_user(), parent->bucket_name(), obj_name, bl);
633 MkObjResult mkr{nullptr, -EINVAL};
634
635 rc = rgwlib.get_fe()->execute_req(&req);
636 rc2 = req.get_ret();
637
638 if ((rc == 0) &&
639 (rc2 == 0)) {
640 /* XXX atomicity */
641 LookupFHResult fhr = lookup_fh(parent, name, RGWFileHandle::FLAG_CREATE |
642 RGWFileHandle::FLAG_LOCK);
643 RGWFileHandle* rgw_fh = get<0>(fhr);
644 if (rgw_fh) {
645 if (get<1>(fhr) & RGWFileHandle::FLAG_CREATE) {
646 /* fill in stat data */
647 real_time t = real_clock::now();
648 rgw_fh->create_stat(st, mask);
649 rgw_fh->set_times(t);
650
651 parent->set_mtime(real_clock::to_timespec(t));
652 parent->set_ctime(real_clock::to_timespec(t));
653 }
654 if (st)
655 (void) rgw_fh->stat(st);
656 get<0>(mkr) = rgw_fh;
657 rgw_fh->mtx.unlock();
658 } else
659 rc = -EIO;
660 }
661
662 get<1>(mkr) = rc;
663
664 return mkr;
665 } /* RGWLibFS::create */
666
667 int RGWLibFS::getattr(RGWFileHandle* rgw_fh, struct stat* st)
668 {
669 switch(rgw_fh->fh.fh_type) {
670 case RGW_FS_TYPE_FILE:
671 {
672 if (rgw_fh->deleted())
673 return -ESTALE;
674 }
675 break;
676 default:
677 break;
678 };
679
680 return rgw_fh->stat(st);
681 } /* RGWLibFS::getattr */
682
683 int RGWLibFS::setattr(RGWFileHandle* rgw_fh, struct stat* st, uint32_t mask,
684 uint32_t flags)
685 {
686 int rc, rc2;
687 buffer::list ux_key, ux_attrs;
688
689 lock_guard guard(rgw_fh->mtx);
690
691 switch(rgw_fh->fh.fh_type) {
692 case RGW_FS_TYPE_FILE:
693 {
694 if (rgw_fh->deleted())
695 return -ESTALE;
696 }
697 break;
698 default:
699 break;
700 };
701
702 string obj_name{rgw_fh->relative_object_name()};
703
31f18b77
FG
704 if (rgw_fh->is_dir() &&
705 (likely(! rgw_fh->is_bucket()))) {
7c673cae
FG
706 obj_name += "/";
707 }
708
709 RGWSetAttrsRequest req(cct, get_user(), rgw_fh->bucket_name(), obj_name);
710
711 rgw_fh->create_stat(st, mask);
712 rgw_fh->encode_attrs(ux_key, ux_attrs);
713
714 /* save attrs */
715 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
716 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
717
718 rc = rgwlib.get_fe()->execute_req(&req);
719 rc2 = req.get_ret();
720
721 if (rc == -ENOENT) {
722 /* special case: materialize placeholder dir */
723 buffer::list bl;
724 RGWPutObjRequest req(get_context(), get_user(), rgw_fh->bucket_name(),
725 obj_name, bl);
726
727 rgw_fh->encode_attrs(ux_key, ux_attrs); /* because std::moved */
728
729 /* save attrs */
730 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
731 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
732
733 rc = rgwlib.get_fe()->execute_req(&req);
734 rc2 = req.get_ret();
735 }
736
737 if ((rc != 0) || (rc2 != 0)) {
738 return -EIO;
739 }
740
741 rgw_fh->set_ctime(real_clock::to_timespec(real_clock::now()));
742
743 return 0;
744 } /* RGWLibFS::setattr */
745
224ce89b 746 /* called under rgw_fh->mtx held */
3efd9988 747 void RGWLibFS::update_fh(RGWFileHandle *rgw_fh)
224ce89b
WB
748 {
749 int rc, rc2;
750 string obj_name{rgw_fh->relative_object_name()};
751 buffer::list ux_key, ux_attrs;
752
753 if (rgw_fh->is_dir() &&
754 (likely(! rgw_fh->is_bucket()))) {
755 obj_name += "/";
756 }
757
758 lsubdout(get_context(), rgw, 17)
759 << __func__
3efd9988 760 << " update old versioned fh : " << obj_name
224ce89b
WB
761 << dendl;
762
763 RGWSetAttrsRequest req(cct, get_user(), rgw_fh->bucket_name(), obj_name);
764
765 rgw_fh->encode_attrs(ux_key, ux_attrs);
766
224ce89b 767 req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
3efd9988 768 req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
224ce89b
WB
769
770 rc = rgwlib.get_fe()->execute_req(&req);
771 rc2 = req.get_ret();
772
773 if ((rc != 0) || (rc2 != 0)) {
774 lsubdout(get_context(), rgw, 17)
775 << __func__
3efd9988 776 << " update fh failed : " << obj_name
224ce89b
WB
777 << dendl;
778 }
3efd9988 779 } /* RGWLibFS::update_fh */
224ce89b 780
7c673cae
FG
781 void RGWLibFS::close()
782 {
783 state.flags |= FLAG_CLOSED;
784
785 class ObjUnref
786 {
787 RGWLibFS* fs;
788 public:
3efd9988 789 ObjUnref(RGWLibFS* _fs) : fs(_fs) {}
7c673cae
FG
790 void operator()(RGWFileHandle* fh) const {
791 lsubdout(fs->get_context(), rgw, 5)
792 << __func__
793 << fh->name
794 << " before ObjUnref refs=" << fh->get_refcnt()
795 << dendl;
31f18b77 796 fs->unref(fh);
7c673cae
FG
797 }
798 };
799
800 /* force cache drain, forces objects to evict */
801 fh_cache.drain(ObjUnref(this),
802 RGWFileHandle::FHCache::FLAG_LOCK);
803 rgwlib.get_fe()->get_process()->unregister_fs(this);
804 rele();
805 } /* RGWLibFS::close */
806
807 inline std::ostream& operator<<(std::ostream &os, struct timespec const &ts) {
808 os << "<timespec: tv_sec=";
809 os << ts.tv_sec;
810 os << "; tv_nsec=";
811 os << ts.tv_nsec;
812 os << ">";
813 return os;
814 }
815
816 std::ostream& operator<<(std::ostream &os, RGWLibFS::event const &ev) {
817 os << "<event:";
818 switch (ev.t) {
819 case RGWLibFS::event::type::READDIR:
820 os << "type=READDIR;";
821 break;
822 default:
823 os << "type=UNKNOWN;";
824 break;
825 };
826 os << "fid=" << ev.fhk.fh_hk.bucket << ":" << ev.fhk.fh_hk.object
827 << ";ts=" << ev.ts << ">";
828 return os;
829 }
830
831 void RGWLibFS::gc()
832 {
833 using std::get;
834 using directory = RGWFileHandle::directory;
835
836 /* dirent invalidate timeout--basically, the upper-bound on
837 * inconsistency with the S3 namespace */
838 auto expire_s
839 = get_context()->_conf->rgw_nfs_namespace_expire_secs;
840
841 /* max events to gc in one cycle */
c07f9fc5 842 uint32_t max_ev = get_context()->_conf->rgw_nfs_max_gc;
7c673cae
FG
843
844 struct timespec now, expire_ts;
845 event_vector ve;
846 bool stop = false;
847 std::deque<event> &events = state.events;
848
849 do {
850 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
851 lsubdout(get_context(), rgw, 15)
852 << "GC: top of expire loop"
853 << " now=" << now
854 << " expire_s=" << expire_s
855 << dendl;
856 {
857 lock_guard guard(state.mtx); /* LOCKED */
858 /* just return if no events */
859 if (events.empty()) {
860 return;
861 }
862 uint32_t _max_ev =
863 (events.size() < 500) ? max_ev : (events.size() / 4);
864 for (uint32_t ix = 0; (ix < _max_ev) && (events.size() > 0); ++ix) {
865 event& ev = events.front();
866 expire_ts = ev.ts;
867 expire_ts.tv_sec += expire_s;
868 if (expire_ts > now) {
869 stop = true;
870 break;
871 }
872 ve.push_back(ev);
873 events.pop_front();
874 }
875 } /* anon */
876 /* !LOCKED */
877 for (auto& ev : ve) {
878 lsubdout(get_context(), rgw, 15)
879 << "try-expire ev: " << ev << dendl;
880 if (likely(ev.t == event::type::READDIR)) {
881 RGWFileHandle* rgw_fh = lookup_handle(ev.fhk.fh_hk);
882 lsubdout(get_context(), rgw, 15)
883 << "ev rgw_fh: " << rgw_fh << dendl;
884 if (rgw_fh) {
885 RGWFileHandle::directory* d;
886 if (unlikely(! rgw_fh->is_dir())) {
887 lsubdout(get_context(), rgw, 0)
888 << __func__
889 << " BUG non-directory found with READDIR event "
890 << "(" << rgw_fh->bucket_name() << ","
891 << rgw_fh->object_name() << ")"
892 << dendl;
893 goto rele;
894 }
895 /* maybe clear state */
896 d = get<directory>(&rgw_fh->variant_type);
897 if (d) {
898 struct timespec ev_ts = ev.ts;
899 lock_guard guard(rgw_fh->mtx);
900 struct timespec d_last_readdir = d->last_readdir;
901 if (unlikely(ev_ts < d_last_readdir)) {
902 /* readdir cycle in progress, don't invalidate */
903 lsubdout(get_context(), rgw, 15)
904 << "GC: delay expiration for "
905 << rgw_fh->object_name()
906 << " ev.ts=" << ev_ts
907 << " last_readdir=" << d_last_readdir
908 << dendl;
909 continue;
910 } else {
911 lsubdout(get_context(), rgw, 15)
912 << "GC: expiring "
913 << rgw_fh->object_name()
914 << dendl;
915 rgw_fh->clear_state();
916 rgw_fh->invalidate();
917 }
918 }
919 rele:
920 unref(rgw_fh);
921 } /* rgw_fh */
922 } /* event::type::READDIR */
923 } /* ev */
924 ve.clear();
925 } while (! (stop || shutdown));
926 } /* RGWLibFS::gc */
927
928 std::ostream& operator<<(std::ostream &os,
929 RGWFileHandle const &rgw_fh)
930 {
931 const auto& fhk = rgw_fh.get_key();
932 const auto& fh = const_cast<RGWFileHandle&>(rgw_fh).get_fh();
933 os << "<RGWFileHandle:";
934 os << "addr=" << &rgw_fh << ";";
935 switch (fh->fh_type) {
936 case RGW_FS_TYPE_DIRECTORY:
937 os << "type=DIRECTORY;";
938 break;
939 case RGW_FS_TYPE_FILE:
940 os << "type=FILE;";
941 break;
942 default:
943 os << "type=UNKNOWN;";
944 break;
945 };
946 os << "fid=" << fhk.fh_hk.bucket << ":" << fhk.fh_hk.object << ";";
947 os << "name=" << rgw_fh.object_name() << ";";
948 os << "refcnt=" << rgw_fh.get_refcnt() << ";";
949 os << ">";
950 return os;
951 }
952
953 RGWFileHandle::~RGWFileHandle() {
7c673cae 954 /* cond-unref parent */
3efd9988 955 if (parent && (! parent->is_mount())) {
7c673cae
FG
956 /* safe because if parent->unref causes its deletion,
957 * there are a) by refcnt, no other objects/paths pointing
958 * to it and b) by the semantics of valid iteration of
959 * fh_lru (observed, e.g., by cohort_lru<T,...>::drain())
960 * no unsafe iterators reaching it either--n.b., this constraint
961 * is binding oncode which may in future attempt to e.g.,
962 * cause the eviction of objects in LRU order */
31f18b77 963 (void) get_fs()->unref(parent);
7c673cae
FG
964 }
965 }
966
967 void RGWFileHandle::encode_attrs(ceph::buffer::list& ux_key1,
968 ceph::buffer::list& ux_attrs1)
969 {
970 fh_key fhk(this->fh.fh_hk);
971 rgw::encode(fhk, ux_key1);
972 rgw::encode(*this, ux_attrs1);
973 } /* RGWFileHandle::encode_attrs */
974
3efd9988
FG
975 DecodeAttrsResult RGWFileHandle::decode_attrs(const ceph::buffer::list* ux_key1,
976 const ceph::buffer::list* ux_attrs1)
7c673cae 977 {
3efd9988 978 DecodeAttrsResult dar { false, false };
7c673cae
FG
979 fh_key fhk;
980 auto bl_iter_key1 = const_cast<buffer::list*>(ux_key1)->begin();
981 rgw::decode(fhk, bl_iter_key1);
224ce89b
WB
982 if (fhk.version >= 2) {
983 assert(this->fh.fh_hk == fhk.fh_hk);
984 } else {
3efd9988 985 get<0>(dar) = true;
224ce89b 986 }
7c673cae
FG
987
988 auto bl_iter_unix1 = const_cast<buffer::list*>(ux_attrs1)->begin();
989 rgw::decode(*this, bl_iter_unix1);
3efd9988
FG
990 if (this->state.version < 2) {
991 get<1>(dar) = true;
992 }
224ce89b 993
3efd9988 994 return dar;
7c673cae
FG
995 } /* RGWFileHandle::decode_attrs */
996
997 bool RGWFileHandle::reclaim() {
998 lsubdout(fs->get_context(), rgw, 17)
999 << __func__ << " " << *this
1000 << dendl;
b32b8144 1001 /* in the non-delete case, handle may still be in handle table */
7c673cae 1002 if (fh_hook.is_linked()) {
b32b8144
FG
1003 /* in this case, we are being called from a context which holds
1004 * the partition lock */
1005 fs->fh_cache.remove(fh.fh_hk.object, this, FHCache::FLAG_NONE);
7c673cae
FG
1006 }
1007 return true;
1008 } /* RGWFileHandle::reclaim */
1009
1010 bool RGWFileHandle::has_children() const
1011 {
1012 if (unlikely(! is_dir()))
1013 return false;
1014
1015 RGWRMdirCheck req(fs->get_context(), fs->get_user(), this);
1016 int rc = rgwlib.get_fe()->execute_req(&req);
1017 if (! rc) {
1018 return req.valid && req.has_children;
1019 }
1020
1021 return false;
1022 }
1023
3efd9988
FG
1024 std::ostream& operator<<(std::ostream &os,
1025 RGWFileHandle::readdir_offset const &offset)
1026 {
1027 using boost::get;
1028 if (unlikely(!! get<uint64_t*>(&offset))) {
1029 uint64_t* ioff = get<uint64_t*>(offset);
1030 os << *ioff;
1031 }
1032 else
1033 os << get<const char*>(offset);
1034 return os;
1035 }
1036
1037 int RGWFileHandle::readdir(rgw_readdir_cb rcb, void *cb_arg,
1038 readdir_offset offset,
7c673cae
FG
1039 bool *eof, uint32_t flags)
1040 {
1041 using event = RGWLibFS::event;
3efd9988 1042 using boost::get;
7c673cae
FG
1043 int rc = 0;
1044 struct timespec now;
1045 CephContext* cct = fs->get_context();
1046
7c673cae
FG
1047 directory* d = get<directory>(&variant_type);
1048 if (d) {
1049 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
1050 lock_guard guard(mtx);
1051 d->last_readdir = now;
1052 }
1053
3efd9988
FG
1054 bool initial_off;
1055 if (likely(!! get<const char*>(&offset))) {
1056 initial_off = ! get<const char*>(offset);
1057 } else {
1058 initial_off = (*get<uint64_t*>(offset) == 0);
1059 }
1060
7c673cae
FG
1061 if (is_root()) {
1062 RGWListBucketsRequest req(cct, fs->get_user(), this, rcb, cb_arg,
1063 offset);
1064 rc = rgwlib.get_fe()->execute_req(&req);
1065 if (! rc) {
1066 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
1067 lock_guard guard(mtx);
1068 state.atime = now;
3efd9988 1069 if (initial_off)
7c673cae
FG
1070 set_nlink(2);
1071 inc_nlink(req.d_count);
1072 *eof = req.eof();
1073 event ev(event::type::READDIR, get_key(), state.atime);
31f18b77 1074 lock_guard sguard(fs->state.mtx);
7c673cae
FG
1075 fs->state.push_event(ev);
1076 }
1077 } else {
1078 RGWReaddirRequest req(cct, fs->get_user(), this, rcb, cb_arg, offset);
1079 rc = rgwlib.get_fe()->execute_req(&req);
1080 if (! rc) {
1081 (void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
1082 lock_guard guard(mtx);
1083 state.atime = now;
3efd9988 1084 if (initial_off)
7c673cae
FG
1085 set_nlink(2);
1086 inc_nlink(req.d_count);
1087 *eof = req.eof();
1088 event ev(event::type::READDIR, get_key(), state.atime);
31f18b77 1089 lock_guard sguard(fs->state.mtx);
7c673cae
FG
1090 fs->state.push_event(ev);
1091 }
1092 }
1093
1094 lsubdout(fs->get_context(), rgw, 15)
1095 << __func__
1096 << " final link count=" << state.nlink
1097 << dendl;
1098
1099 return rc;
1100 } /* RGWFileHandle::readdir */
1101
1102 int RGWFileHandle::write(uint64_t off, size_t len, size_t *bytes_written,
1103 void *buffer)
1104 {
1105 using std::get;
1106 using WriteCompletion = RGWLibFS::WriteCompletion;
1107
1108 lock_guard guard(mtx);
1109
1110 int rc = 0;
1111
1112 file* f = get<file>(&variant_type);
1113 if (! f)
1114 return -EISDIR;
1115
1116 if (deleted()) {
1117 lsubdout(fs->get_context(), rgw, 5)
1118 << __func__
1119 << " write attempted on deleted object "
1120 << this->object_name()
1121 << dendl;
1122 /* zap write transaction, if any */
1123 if (f->write_req) {
1124 delete f->write_req;
1125 f->write_req = nullptr;
1126 }
1127 return -ESTALE;
1128 }
1129
1130 if (! f->write_req) {
1131 /* guard--we do not support (e.g., COW-backed) partial writes */
1132 if (off != 0) {
1133 lsubdout(fs->get_context(), rgw, 5)
1134 << __func__
1135 << " " << object_name()
1136 << " non-0 initial write position " << off
1137 << dendl;
1138 return -EIO;
1139 }
1140
1141 /* start */
1142 std::string object_name = relative_object_name();
1143 f->write_req =
1144 new RGWWriteRequest(fs->get_context(), fs->get_user(), this,
1145 bucket_name(), object_name);
1146 rc = rgwlib.get_fe()->start_req(f->write_req);
1147 if (rc < 0) {
1148 lsubdout(fs->get_context(), rgw, 5)
1149 << __func__
1150 << this->object_name()
1151 << " write start failed " << off
1152 << " (" << rc << ")"
1153 << dendl;
1154 /* zap failed write transaction */
1155 delete f->write_req;
1156 f->write_req = nullptr;
1157 return -EIO;
1158 } else {
1159 if (stateless_open()) {
1160 /* start write timer */
1161 f->write_req->timer_id =
1162 RGWLibFS::write_timer.add_event(
1163 std::chrono::seconds(RGWLibFS::write_completion_interval_s),
1164 WriteCompletion(*this));
1165 }
1166 }
1167 }
1168
3efd9988
FG
1169 int overlap = 0;
1170 if ((static_cast<off_t>(off) < f->write_req->real_ofs) &&
1171 ((f->write_req->real_ofs - off) <= len)) {
1172 overlap = f->write_req->real_ofs - off;
1173 off = f->write_req->real_ofs;
1174 buffer = static_cast<char*>(buffer) + overlap;
1175 len -= overlap;
1176 }
1177
7c673cae
FG
1178 buffer::list bl;
1179 /* XXXX */
1180#if 0
1181 bl.push_back(
1182 buffer::create_static(len, static_cast<char*>(buffer)));
1183#else
1184 bl.push_back(
1185 buffer::copy(static_cast<char*>(buffer), len));
1186#endif
1187
1188 f->write_req->put_data(off, bl);
1189 rc = f->write_req->exec_continue();
1190
1191 if (rc == 0) {
1192 size_t min_size = off + len;
1193 if (min_size > get_size())
1194 set_size(min_size);
1195 if (stateless_open()) {
1196 /* bump write timer */
1197 RGWLibFS::write_timer.adjust_event(
1198 f->write_req->timer_id, std::chrono::seconds(10));
1199 }
1200 } else {
1201 /* continuation failed (e.g., non-contiguous write position) */
1202 lsubdout(fs->get_context(), rgw, 5)
1203 << __func__
1204 << object_name()
1205 << " failed write at position " << off
1206 << " (fails write transaction) "
1207 << dendl;
1208 /* zap failed write transaction */
1209 delete f->write_req;
1210 f->write_req = nullptr;
1211 rc = -EIO;
1212 }
1213
3efd9988 1214 *bytes_written = (rc == 0) ? (len + overlap) : 0;
7c673cae
FG
1215 return rc;
1216 } /* RGWFileHandle::write */
1217
1218 int RGWFileHandle::write_finish(uint32_t flags)
1219 {
1220 unique_lock guard{mtx, std::defer_lock};
1221 int rc = 0;
1222
1223 if (! (flags & FLAG_LOCKED)) {
1224 guard.lock();
1225 }
1226
1227 file* f = get<file>(&variant_type);
1228 if (f && (f->write_req)) {
1229 lsubdout(fs->get_context(), rgw, 10)
1230 << __func__
1231 << " finishing write trans on " << object_name()
1232 << dendl;
1233 rc = rgwlib.get_fe()->finish_req(f->write_req);
1234 if (! rc) {
1235 rc = f->write_req->get_ret();
1236 }
1237 delete f->write_req;
1238 f->write_req = nullptr;
1239 }
1240
1241 return rc;
1242 } /* RGWFileHandle::write_finish */
1243
1244 int RGWFileHandle::close()
1245 {
1246 lock_guard guard(mtx);
1247
1248 int rc = write_finish(FLAG_LOCKED);
1249
1250 flags &= ~FLAG_OPEN;
31f18b77
FG
1251 flags &= ~FLAG_STATELESS_OPEN;
1252
7c673cae
FG
1253 return rc;
1254 } /* RGWFileHandle::close */
1255
1256 RGWFileHandle::file::~file()
1257 {
1258 delete write_req;
1259 }
1260
1261 void RGWFileHandle::clear_state()
1262 {
1263 directory* d = get<directory>(&variant_type);
1264 if (d) {
1265 state.nlink = 2;
1266 d->last_marker = rgw_obj_key{};
1267 }
1268 }
1269
1270 void RGWFileHandle::invalidate() {
1271 RGWLibFS *fs = get_fs();
1272 if (fs->invalidate_cb) {
1273 fs->invalidate_cb(fs->invalidate_arg, get_key().fh_hk);
1274 }
1275 }
1276
1277 int RGWWriteRequest::exec_start() {
1278 struct req_state* s = get_state();
1279
224ce89b
WB
1280 auto compression_type =
1281 get_store()->get_zone_params().get_compression_type(
1282 s->bucket_info.placement_rule);
1283
7c673cae
FG
1284 /* not obviously supportable */
1285 assert(! dlo_manifest);
1286 assert(! slo_info);
1287
1288 perfcounter->inc(l_rgw_put);
1289 op_ret = -EINVAL;
1290
1291 if (s->object.empty()) {
1292 ldout(s->cct, 0) << __func__ << " called on empty object" << dendl;
1293 goto done;
1294 }
1295
1296 op_ret = get_params();
1297 if (op_ret < 0)
1298 goto done;
1299
1300 op_ret = get_system_versioning_params(s, &olh_epoch, &version_id);
1301 if (op_ret < 0) {
1302 goto done;
1303 }
1304
1305 /* user-supplied MD5 check skipped (not supplied) */
1306 /* early quota check skipped--we don't have size yet */
1307 /* skipping user-supplied etag--we might have one in future, but
1308 * like data it and other attrs would arrive after open */
1309 processor = select_processor(*static_cast<RGWObjectCtx *>(s->obj_ctx),
1310 &multipart);
1311 op_ret = processor->prepare(get_store(), NULL);
224ce89b
WB
1312 if (op_ret < 0) {
1313 ldout(s->cct, 20) << "processor->prepare() returned ret=" << op_ret
1314 << dendl;
1315 goto done;
1316 }
1317
1318 filter = processor;
1319 if (compression_type != "none") {
1320 plugin = Compressor::create(s->cct, compression_type);
1321 if (! plugin) {
1322 ldout(s->cct, 1) << "Cannot load plugin for rgw_compression_type "
1323 << compression_type << dendl;
1324 } else {
1325 compressor.emplace(s->cct, plugin, filter);
1326 filter = &*compressor;
1327 }
1328 }
7c673cae
FG
1329
1330 done:
1331 return op_ret;
1332 } /* exec_start */
1333
1334 int RGWWriteRequest::exec_continue()
1335 {
1336 struct req_state* s = get_state();
1337 op_ret = 0;
1338
1339 /* check guards (e.g., contig write) */
1340 if (eio)
1341 return -EIO;
1342
1343 size_t len = data.length();
1344 if (! len)
1345 return 0;
1346
1347 /* XXX we are currently synchronous--supplied data buffers cannot
1348 * be used after the caller returns */
1349 bool need_to_wait = true;
1350 bufferlist orig_data;
1351
1352 if (need_to_wait) {
1353 orig_data = data;
1354 }
1355 hash.Update((const byte *)data.c_str(), data.length());
224ce89b 1356 op_ret = put_data_and_throttle(filter, data, ofs, need_to_wait);
7c673cae
FG
1357 if (op_ret < 0) {
1358 if (!need_to_wait || op_ret != -EEXIST) {
1359 ldout(s->cct, 20) << "processor->thottle_data() returned ret="
1360 << op_ret << dendl;
1361 goto done;
1362 }
1363
1364 ldout(s->cct, 5) << "NOTICE: processor->throttle_data() returned -EEXIST, need to restart write" << dendl;
1365
1366 /* restore original data */
1367 data.swap(orig_data);
1368
1369 /* restart processing with different oid suffix */
1370 dispose_processor(processor);
1371 processor = select_processor(*static_cast<RGWObjectCtx *>(s->obj_ctx),
1372 &multipart);
224ce89b 1373 filter = processor;
7c673cae
FG
1374
1375 string oid_rand;
1376 char buf[33];
1377 gen_rand_alphanumeric(get_store()->ctx(), buf, sizeof(buf) - 1);
1378 oid_rand.append(buf);
1379
1380 op_ret = processor->prepare(get_store(), &oid_rand);
1381 if (op_ret < 0) {
1382 ldout(s->cct, 0) << "ERROR: processor->prepare() returned "
1383 << op_ret << dendl;
1384 goto done;
1385 }
1386
224ce89b
WB
1387 /* restore compression filter, if any */
1388 if (compressor) {
1389 compressor.emplace(s->cct, plugin, filter);
1390 filter = &*compressor;
1391 }
1392
1393 op_ret = put_data_and_throttle(filter, data, ofs, false);
7c673cae
FG
1394 if (op_ret < 0) {
1395 goto done;
1396 }
1397 }
1398 bytes_written += len;
1399
1400 done:
1401 return op_ret;
1402 } /* exec_continue */
1403
1404 int RGWWriteRequest::exec_finish()
1405 {
1406 buffer::list bl, aclbl, ux_key, ux_attrs;
1407 map<string, string>::iterator iter;
1408 char calc_md5[CEPH_CRYPTO_MD5_DIGESTSIZE * 2 + 1];
1409 unsigned char m[CEPH_CRYPTO_MD5_DIGESTSIZE];
1410 struct req_state* s = get_state();
1411
1412 size_t osize = rgw_fh->get_size();
1413 struct timespec octime = rgw_fh->get_ctime();
1414 struct timespec omtime = rgw_fh->get_mtime();
1415 real_time appx_t = real_clock::now();
1416
3efd9988 1417 s->obj_size = bytes_written;
7c673cae
FG
1418 perfcounter->inc(l_rgw_put_b, s->obj_size);
1419
1420 op_ret = get_store()->check_quota(s->bucket_owner.get_id(), s->bucket,
1421 user_quota, bucket_quota, s->obj_size);
1422 if (op_ret < 0) {
1423 goto done;
1424 }
1425
3efd9988
FG
1426 op_ret = get_store()->check_bucket_shards(s->bucket_info, s->bucket,
1427 bucket_quota);
31f18b77
FG
1428 if (op_ret < 0) {
1429 goto done;
1430 }
1431
7c673cae
FG
1432 hash.Final(m);
1433
224ce89b
WB
1434 if (compressor && compressor->is_compressed()) {
1435 bufferlist tmp;
1436 RGWCompressionInfo cs_info;
1437 cs_info.compression_type = plugin->get_type_name();
1438 cs_info.orig_size = s->obj_size;
1439 cs_info.blocks = std::move(compressor->get_compression_blocks());
1440 ::encode(cs_info, tmp);
1441 attrs[RGW_ATTR_COMPRESSION] = tmp;
1442 ldout(s->cct, 20) << "storing " << RGW_ATTR_COMPRESSION
1443 << " with type=" << cs_info.compression_type
1444 << ", orig_size=" << cs_info.orig_size
1445 << ", blocks=" << cs_info.blocks.size() << dendl;
1446 }
1447
7c673cae
FG
1448 buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5);
1449 etag = calc_md5;
1450
1451 bl.append(etag.c_str(), etag.size() + 1);
1452 emplace_attr(RGW_ATTR_ETAG, std::move(bl));
1453
1454 policy.encode(aclbl);
1455 emplace_attr(RGW_ATTR_ACL, std::move(aclbl));
1456
1457 /* unix attrs */
1458 rgw_fh->set_mtime(real_clock::to_timespec(appx_t));
1459 rgw_fh->set_ctime(real_clock::to_timespec(appx_t));
1460 rgw_fh->set_size(bytes_written);
1461 rgw_fh->encode_attrs(ux_key, ux_attrs);
1462
1463 emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
1464 emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
1465
1466 for (iter = s->generic_attrs.begin(); iter != s->generic_attrs.end();
1467 ++iter) {
1468 buffer::list& attrbl = attrs[iter->first];
1469 const string& val = iter->second;
1470 attrbl.append(val.c_str(), val.size() + 1);
1471 }
1472
3efd9988
FG
1473 op_ret = rgw_get_request_metadata(s->cct, s->info, attrs);
1474 if (op_ret < 0) {
1475 goto done;
1476 }
7c673cae
FG
1477 encode_delete_at_attr(delete_at, attrs);
1478
1479 /* Add a custom metadata to expose the information whether an object
1480 * is an SLO or not. Appending the attribute must be performed AFTER
1481 * processing any input from user in order to prohibit overwriting. */
1482 if (unlikely(!! slo_info)) {
1483 buffer::list slo_userindicator_bl;
1484 ::encode("True", slo_userindicator_bl);
1485 emplace_attr(RGW_ATTR_SLO_UINDICATOR, std::move(slo_userindicator_bl));
1486 }
1487
1488 op_ret = processor->complete(s->obj_size, etag, &mtime, real_time(), attrs,
1489 (delete_at ? *delete_at : real_time()),
1490 if_match, if_nomatch);
1491 if (op_ret != 0) {
1492 /* revert attr updates */
1493 rgw_fh->set_mtime(omtime);
1494 rgw_fh->set_ctime(octime);
1495 rgw_fh->set_size(osize);
1496 }
1497
1498 done:
1499 dispose_processor(processor);
1500 perfcounter->tinc(l_rgw_put_lat,
1501 (ceph_clock_now() - s->time));
1502 return op_ret;
1503 } /* exec_finish */
1504
1505} /* namespace rgw */
1506
1507/* librgw */
1508extern "C" {
1509
1510void rgwfile_version(int *major, int *minor, int *extra)
1511{
1512 if (major)
1513 *major = LIBRGW_FILE_VER_MAJOR;
1514 if (minor)
1515 *minor = LIBRGW_FILE_VER_MINOR;
1516 if (extra)
1517 *extra = LIBRGW_FILE_VER_EXTRA;
1518}
1519
1520/*
1521 attach rgw namespace
1522*/
1523 int rgw_mount(librgw_t rgw, const char *uid, const char *acc_key,
1524 const char *sec_key, struct rgw_fs **rgw_fs,
1525 uint32_t flags)
1526{
1527 int rc = 0;
1528
1529 /* stash access data for "mount" */
1530 RGWLibFS* new_fs = new RGWLibFS(static_cast<CephContext*>(rgw), uid, acc_key,
3efd9988
FG
1531 sec_key, "/");
1532 assert(new_fs);
1533
1534 rc = new_fs->authorize(rgwlib.get_store());
1535 if (rc != 0) {
1536 delete new_fs;
1537 return -EINVAL;
1538 }
1539
1540 /* register fs for shared gc */
1541 rgwlib.get_fe()->get_process()->register_fs(new_fs);
1542
1543 struct rgw_fs *fs = new_fs->get_fs();
1544 fs->rgw = rgw;
1545
1546 /* XXX we no longer assume "/" is unique, but we aren't tracking the
1547 * roots atm */
1548
1549 *rgw_fs = fs;
1550
1551 return 0;
1552}
1553
1554int rgw_mount2(librgw_t rgw, const char *uid, const char *acc_key,
1555 const char *sec_key, const char *root, struct rgw_fs **rgw_fs,
1556 uint32_t flags)
1557{
1558 int rc = 0;
1559
1560 /* stash access data for "mount" */
1561 RGWLibFS* new_fs = new RGWLibFS(static_cast<CephContext*>(rgw), uid, acc_key,
1562 sec_key, root);
7c673cae
FG
1563 assert(new_fs);
1564
1565 rc = new_fs->authorize(rgwlib.get_store());
1566 if (rc != 0) {
1567 delete new_fs;
1568 return -EINVAL;
1569 }
1570
1571 /* register fs for shared gc */
1572 rgwlib.get_fe()->get_process()->register_fs(new_fs);
1573
1574 struct rgw_fs *fs = new_fs->get_fs();
1575 fs->rgw = rgw;
1576
1577 /* XXX we no longer assume "/" is unique, but we aren't tracking the
1578 * roots atm */
1579
1580 *rgw_fs = fs;
1581
1582 return 0;
1583}
1584
1585/*
1586 register invalidate callbacks
1587*/
1588int rgw_register_invalidate(struct rgw_fs *rgw_fs, rgw_fh_callback_t cb,
1589 void *arg, uint32_t flags)
1590
1591{
1592 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1593 return fs->register_invalidate(cb, arg, flags);
1594}
1595
1596/*
1597 detach rgw namespace
1598*/
1599int rgw_umount(struct rgw_fs *rgw_fs, uint32_t flags)
1600{
1601 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1602 fs->close();
7c673cae
FG
1603 return 0;
1604}
1605
1606/*
1607 get filesystem attributes
1608*/
1609int rgw_statfs(struct rgw_fs *rgw_fs,
1610 struct rgw_file_handle *parent_fh,
1611 struct rgw_statvfs *vfs_st, uint32_t flags)
1612{
1613 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1614
1615 /* XXX for now, just publish a huge capacity and
1616 * limited utiliztion */
1617 vfs_st->f_bsize = 1024*1024 /* 1M */;
1618 vfs_st->f_frsize = 1024; /* minimal allocation unit (who cares) */
1619 vfs_st->f_blocks = UINT64_MAX;
1620 vfs_st->f_bfree = UINT64_MAX;
1621 vfs_st->f_bavail = UINT64_MAX;
1622 vfs_st->f_files = 1024; /* object count, do we have an est? */
1623 vfs_st->f_ffree = UINT64_MAX;
3efd9988
FG
1624 vfs_st->f_fsid[0] = fs->get_fsid();
1625 vfs_st->f_fsid[1] = fs->get_fsid();
7c673cae
FG
1626 vfs_st->f_flag = 0;
1627 vfs_st->f_namemax = 4096;
1628 return 0;
1629}
1630
1631/*
1632 generic create -- create an empty regular file
1633*/
1634int rgw_create(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh,
1635 const char *name, struct stat *st, uint32_t mask,
1636 struct rgw_file_handle **fh, uint32_t posix_flags,
1637 uint32_t flags)
1638{
1639 using std::get;
1640
1641 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1642 RGWFileHandle* parent = get_rgwfh(parent_fh);
1643
1644 if ((! parent) ||
1645 (parent->is_root()) ||
1646 (parent->is_file())) {
1647 /* bad parent */
1648 return -EINVAL;
1649 }
1650
1651 MkObjResult fhr = fs->create(parent, name, st, mask, flags);
1652 RGWFileHandle *nfh = get<0>(fhr); // nullptr if !success
1653
1654 if (nfh)
1655 *fh = nfh->get_fh();
1656
1657 return get<1>(fhr);
1658} /* rgw_create */
1659
1660/*
1661 create a new directory
1662*/
1663int rgw_mkdir(struct rgw_fs *rgw_fs,
1664 struct rgw_file_handle *parent_fh,
1665 const char *name, struct stat *st, uint32_t mask,
1666 struct rgw_file_handle **fh, uint32_t flags)
1667{
1668 using std::get;
1669
1670 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1671 RGWFileHandle* parent = get_rgwfh(parent_fh);
1672
1673 if (! parent) {
1674 /* bad parent */
1675 return -EINVAL;
1676 }
1677
1678 MkObjResult fhr = fs->mkdir(parent, name, st, mask, flags);
1679 RGWFileHandle *nfh = get<0>(fhr); // nullptr if !success
1680
1681 if (nfh)
1682 *fh = nfh->get_fh();
1683
1684 return get<1>(fhr);
1685} /* rgw_mkdir */
1686
1687/*
1688 rename object
1689*/
1690int rgw_rename(struct rgw_fs *rgw_fs,
1691 struct rgw_file_handle *src, const char* src_name,
1692 struct rgw_file_handle *dst, const char* dst_name,
1693 uint32_t flags)
1694{
1695 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1696
1697 RGWFileHandle* src_fh = get_rgwfh(src);
1698 RGWFileHandle* dst_fh = get_rgwfh(dst);
1699
1700 return fs->rename(src_fh, dst_fh, src_name, dst_name);
1701}
1702
1703/*
1704 remove file or directory
1705*/
1706int rgw_unlink(struct rgw_fs *rgw_fs, struct rgw_file_handle *parent_fh,
1707 const char *name, uint32_t flags)
1708{
1709 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1710 RGWFileHandle* parent = get_rgwfh(parent_fh);
1711
1712 return fs->unlink(parent, name);
1713}
1714
1715/*
1716 lookup object by name (POSIX style)
1717*/
1718int rgw_lookup(struct rgw_fs *rgw_fs,
1719 struct rgw_file_handle *parent_fh, const char* path,
1720 struct rgw_file_handle **fh, uint32_t flags)
1721{
1722 //CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
1723 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1724
1725 RGWFileHandle* parent = get_rgwfh(parent_fh);
1726 if ((! parent) ||
1727 (! parent->is_dir())) {
1728 /* bad parent */
1729 return -EINVAL;
1730 }
1731
1732 RGWFileHandle* rgw_fh;
1733 LookupFHResult fhr;
1734
1735 if (parent->is_root()) {
1736 /* special: parent lookup--note lack of ref()! */
1737 if (unlikely((strcmp(path, "..") == 0) ||
1738 (strcmp(path, "/") == 0))) {
1739 rgw_fh = parent;
1740 } else {
31f18b77
FG
1741 RGWLibFS::BucketStats bstat;
1742 fhr = fs->stat_bucket(parent, path, bstat, RGWFileHandle::FLAG_NONE);
7c673cae
FG
1743 rgw_fh = get<0>(fhr);
1744 if (! rgw_fh)
1745 return -ENOENT;
1746 }
1747 } else {
224ce89b
WB
1748 /* special: after readdir--note extra ref()! */
1749 if (unlikely((strcmp(path, "..") == 0))) {
1750 rgw_fh = parent;
1751 lsubdout(fs->get_context(), rgw, 17)
1752 << __func__ << "BANG"<< *rgw_fh
1753 << dendl;
1754 fs->ref(rgw_fh);
1755 } else {
1756 /* lookup in a readdir callback */
1757 enum rgw_fh_type fh_type = fh_type_of(flags);
1758
1759 uint32_t sl_flags = (flags & RGW_LOOKUP_FLAG_RCB)
1760 ? RGWFileHandle::FLAG_NONE
1761 : RGWFileHandle::FLAG_EXACT_MATCH;
1762
1763 fhr = fs->stat_leaf(parent, path, fh_type, sl_flags);
1764 if (! get<0>(fhr)) {
1765 if (! (flags & RGW_LOOKUP_FLAG_CREATE))
1766 return -ENOENT;
1767 else
1768 fhr = fs->lookup_fh(parent, path, RGWFileHandle::FLAG_CREATE);
1769 }
1770 rgw_fh = get<0>(fhr);
7c673cae 1771 }
7c673cae
FG
1772 } /* !root */
1773
1774 struct rgw_file_handle *rfh = rgw_fh->get_fh();
1775 *fh = rfh;
1776
1777 return 0;
1778} /* rgw_lookup */
1779
1780/*
1781 lookup object by handle (NFS style)
1782*/
1783int rgw_lookup_handle(struct rgw_fs *rgw_fs, struct rgw_fh_hk *fh_hk,
1784 struct rgw_file_handle **fh, uint32_t flags)
1785{
1786 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1787
1788 RGWFileHandle* rgw_fh = fs->lookup_handle(*fh_hk);
1789 if (! rgw_fh) {
1790 /* not found */
1791 return -ENOENT;
1792 }
1793
1794 struct rgw_file_handle *rfh = rgw_fh->get_fh();
1795 *fh = rfh;
1796
1797 return 0;
1798}
1799
1800/*
1801 * release file handle
1802 */
1803int rgw_fh_rele(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
1804 uint32_t flags)
1805{
1806 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1807 RGWFileHandle* rgw_fh = get_rgwfh(fh);
1808
1809 lsubdout(fs->get_context(), rgw, 17)
1810 << __func__ << " " << *rgw_fh
1811 << dendl;
1812
1813 fs->unref(rgw_fh);
1814 return 0;
1815}
1816
1817/*
1818 get unix attributes for object
1819*/
1820int rgw_getattr(struct rgw_fs *rgw_fs,
1821 struct rgw_file_handle *fh, struct stat *st, uint32_t flags)
1822{
1823 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1824 RGWFileHandle* rgw_fh = get_rgwfh(fh);
1825
1826 return fs->getattr(rgw_fh, st);
1827}
1828
1829/*
1830 set unix attributes for object
1831*/
1832int rgw_setattr(struct rgw_fs *rgw_fs,
1833 struct rgw_file_handle *fh, struct stat *st,
1834 uint32_t mask, uint32_t flags)
1835{
1836 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1837 RGWFileHandle* rgw_fh = get_rgwfh(fh);
1838
1839 return fs->setattr(rgw_fh, st, mask, flags);
1840}
1841
1842/*
1843 truncate file
1844*/
1845int rgw_truncate(struct rgw_fs *rgw_fs,
1846 struct rgw_file_handle *fh, uint64_t size, uint32_t flags)
1847{
1848 return 0;
1849}
1850
1851/*
1852 open file
1853*/
1854int rgw_open(struct rgw_fs *rgw_fs,
1855 struct rgw_file_handle *fh, uint32_t posix_flags, uint32_t flags)
1856{
1857 RGWFileHandle* rgw_fh = get_rgwfh(fh);
1858
1859 /* XXX
1860 * need to track specific opens--at least read opens and
1861 * a write open; we need to know when a write open is returned,
1862 * that closes a write transaction
1863 *
1864 * for now, we will support single-open only, it's preferable to
1865 * anything we can otherwise do without access to the NFS state
1866 */
1867 if (! rgw_fh->is_file())
1868 return -EISDIR;
1869
1870 return rgw_fh->open(flags);
1871}
1872
1873/*
1874 close file
1875*/
1876int rgw_close(struct rgw_fs *rgw_fs,
1877 struct rgw_file_handle *fh, uint32_t flags)
1878{
1879 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1880 RGWFileHandle* rgw_fh = get_rgwfh(fh);
1881 int rc = rgw_fh->close(/* XXX */);
1882
1883 if (flags & RGW_CLOSE_FLAG_RELE)
1884 fs->unref(rgw_fh);
1885
1886 return rc;
1887}
1888
1889int rgw_readdir(struct rgw_fs *rgw_fs,
1890 struct rgw_file_handle *parent_fh, uint64_t *offset,
1891 rgw_readdir_cb rcb, void *cb_arg, bool *eof,
1892 uint32_t flags)
1893{
1894 RGWFileHandle* parent = get_rgwfh(parent_fh);
1895 if (! parent) {
1896 /* bad parent */
1897 return -EINVAL;
1898 }
3efd9988
FG
1899
1900 lsubdout(parent->get_fs()->get_context(), rgw, 15)
1901 << __func__
1902 << " offset=" << *offset
1903 << dendl;
1904
1905 if ((*offset == 0) &&
1906 (flags & RGW_READDIR_FLAG_DOTDOT)) {
1907 /* send '.' and '..' with their NFS-defined offsets */
1908 rcb(".", cb_arg, 1, RGW_LOOKUP_FLAG_DIR);
1909 rcb("..", cb_arg, 2, RGW_LOOKUP_FLAG_DIR);
1910 }
1911
7c673cae
FG
1912 int rc = parent->readdir(rcb, cb_arg, offset, eof, flags);
1913 return rc;
3efd9988
FG
1914} /* rgw_readdir */
1915
1916/* enumeration continuing from name */
1917int rgw_readdir2(struct rgw_fs *rgw_fs,
1918 struct rgw_file_handle *parent_fh, const char *name,
1919 rgw_readdir_cb rcb, void *cb_arg, bool *eof,
1920 uint32_t flags)
1921{
1922 RGWFileHandle* parent = get_rgwfh(parent_fh);
1923 if (! parent) {
1924 /* bad parent */
1925 return -EINVAL;
1926 }
1927
1928 lsubdout(parent->get_fs()->get_context(), rgw, 15)
1929 << __func__
1930 << " offset=" << name
1931 << dendl;
1932
1933 if ((! name) &&
1934 (flags & RGW_READDIR_FLAG_DOTDOT)) {
1935 /* send '.' and '..' with their NFS-defined offsets */
1936 rcb(".", cb_arg, 1, RGW_LOOKUP_FLAG_DIR);
1937 rcb("..", cb_arg, 2, RGW_LOOKUP_FLAG_DIR);
1938 }
1939
1940 int rc = parent->readdir(rcb, cb_arg, name, eof, flags);
1941 return rc;
1942} /* rgw_readdir2 */
7c673cae 1943
c07f9fc5
FG
1944/* project offset of dirent name */
1945int rgw_dirent_offset(struct rgw_fs *rgw_fs,
1946 struct rgw_file_handle *parent_fh,
1947 const char *name, int64_t *offset,
1948 uint32_t flags)
1949{
1950 RGWFileHandle* parent = get_rgwfh(parent_fh);
1951 if ((! parent)) {
1952 /* bad parent */
1953 return -EINVAL;
1954 }
1955 std::string sname{name};
1956 int rc = parent->offset_of(sname, offset, flags);
1957 return rc;
1958}
1959
7c673cae
FG
1960/*
1961 read data from file
1962*/
1963int rgw_read(struct rgw_fs *rgw_fs,
1964 struct rgw_file_handle *fh, uint64_t offset,
1965 size_t length, size_t *bytes_read, void *buffer,
1966 uint32_t flags)
1967{
1968 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
1969 RGWFileHandle* rgw_fh = get_rgwfh(fh);
1970
1971 return fs->read(rgw_fh, offset, length, bytes_read, buffer, flags);
1972}
1973
1974/*
1975 write data to file
1976*/
1977int rgw_write(struct rgw_fs *rgw_fs,
1978 struct rgw_file_handle *fh, uint64_t offset,
1979 size_t length, size_t *bytes_written, void *buffer,
1980 uint32_t flags)
1981{
1982 RGWFileHandle* rgw_fh = get_rgwfh(fh);
1983 int rc;
1984
1985 *bytes_written = 0;
1986
1987 if (! rgw_fh->is_file())
1988 return -EISDIR;
1989
3efd9988
FG
1990 if (! rgw_fh->is_open()) {
1991 if (flags & RGW_OPEN_FLAG_V3) {
1992 rc = rgw_fh->open(flags);
1993 if (!! rc)
1994 return rc;
1995 } else
1996 return -EPERM;
1997 }
7c673cae
FG
1998
1999 rc = rgw_fh->write(offset, length, bytes_written, buffer);
2000
2001 return rc;
2002}
2003
2004/*
2005 read data from file (vector)
2006*/
2007class RGWReadV
2008{
2009 buffer::list bl;
2010 struct rgw_vio* vio;
2011
2012public:
2013 RGWReadV(buffer::list& _bl, rgw_vio* _vio) : vio(_vio) {
2014 bl.claim(_bl);
2015 }
2016
2017 struct rgw_vio* get_vio() { return vio; }
2018
2019 const std::list<buffer::ptr>& buffers() { return bl.buffers(); }
2020
2021 unsigned /* XXX */ length() { return bl.length(); }
2022
2023};
2024
2025void rgw_readv_rele(struct rgw_uio *uio, uint32_t flags)
2026{
2027 RGWReadV* rdv = static_cast<RGWReadV*>(uio->uio_p1);
2028 rdv->~RGWReadV();
2029 ::operator delete(rdv);
2030}
2031
2032int rgw_readv(struct rgw_fs *rgw_fs,
2033 struct rgw_file_handle *fh, rgw_uio *uio, uint32_t flags)
2034{
2035#if 0 /* XXX */
2036 CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
2037 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2038 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2039
2040 if (! rgw_fh->is_file())
2041 return -EINVAL;
2042
2043 int rc = 0;
2044
2045 buffer::list bl;
2046 RGWGetObjRequest req(cct, fs->get_user(), rgw_fh->bucket_name(),
2047 rgw_fh->object_name(), uio->uio_offset, uio->uio_resid,
2048 bl);
2049 req.do_hexdump = false;
2050
2051 rc = rgwlib.get_fe()->execute_req(&req);
2052
2053 if (! rc) {
2054 RGWReadV* rdv = static_cast<RGWReadV*>(
2055 ::operator new(sizeof(RGWReadV) +
2056 (bl.buffers().size() * sizeof(struct rgw_vio))));
2057
2058 (void) new (rdv)
2059 RGWReadV(bl, reinterpret_cast<rgw_vio*>(rdv+sizeof(RGWReadV)));
2060
2061 uio->uio_p1 = rdv;
2062 uio->uio_cnt = rdv->buffers().size();
2063 uio->uio_resid = rdv->length();
2064 uio->uio_vio = rdv->get_vio();
2065 uio->uio_rele = rgw_readv_rele;
2066
2067 int ix = 0;
2068 auto& buffers = rdv->buffers();
2069 for (auto& bp : buffers) {
2070 rgw_vio *vio = &(uio->uio_vio[ix]);
2071 vio->vio_base = const_cast<char*>(bp.c_str());
2072 vio->vio_len = bp.length();
2073 vio->vio_u1 = nullptr;
2074 vio->vio_p1 = nullptr;
2075 ++ix;
2076 }
2077 }
2078
2079 return rc;
2080#else
2081 return 0;
2082#endif
2083}
2084
2085/*
2086 write data to file (vector)
2087*/
2088int rgw_writev(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2089 rgw_uio *uio, uint32_t flags)
2090{
2091
2092 return -ENOTSUP;
2093
2094 CephContext* cct = static_cast<CephContext*>(rgw_fs->rgw);
2095 RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
2096 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2097
2098 if (! rgw_fh->is_file())
2099 return -EINVAL;
2100
2101 buffer::list bl;
2102 for (unsigned int ix = 0; ix < uio->uio_cnt; ++ix) {
2103 rgw_vio *vio = &(uio->uio_vio[ix]);
2104 bl.push_back(
2105 buffer::create_static(vio->vio_len,
2106 static_cast<char*>(vio->vio_base)));
2107 }
2108
2109 std::string oname = rgw_fh->relative_object_name();
2110 RGWPutObjRequest req(cct, fs->get_user(), rgw_fh->bucket_name(),
2111 oname, bl);
2112
2113 int rc = rgwlib.get_fe()->execute_req(&req);
2114
2115 /* XXX update size (in request) */
2116
2117 return rc;
2118}
2119
2120/*
2121 sync written data
2122*/
2123int rgw_fsync(struct rgw_fs *rgw_fs, struct rgw_file_handle *handle,
2124 uint32_t flags)
2125{
2126 return 0;
2127}
2128
2129int rgw_commit(struct rgw_fs *rgw_fs, struct rgw_file_handle *fh,
2130 uint64_t offset, uint64_t length, uint32_t flags)
2131{
2132 RGWFileHandle* rgw_fh = get_rgwfh(fh);
2133
2134 return rgw_fh->commit(offset, length, RGWFileHandle::FLAG_NONE);
2135}
2136
2137} /* extern "C" */