auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
if (ux_key && ux_attrs) {
- rgw_fh->decode_attrs(ux_key, ux_attrs);
+ DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
+ if (get<0>(dar) || get<1>(dar)) {
+ update_fh(rgw_fh);
+ }
}
if (! (flags & RGWFileHandle::FLAG_LOCKED)) {
rgw_fh->mtx.unlock();
auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
if (ux_key && ux_attrs) {
- rgw_fh->decode_attrs(ux_key, ux_attrs);
+ DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
+ if (get<0>(dar) || get<1>(dar)) {
+ update_fh(rgw_fh);
+ }
}
}
goto done;
auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
auto ux_attrs = req.get_attr(RGW_ATTR_UNIX1);
if (ux_key && ux_attrs) {
- rgw_fh->decode_attrs(ux_key, ux_attrs);
+ DecodeAttrsResult dar = rgw_fh->decode_attrs(ux_key, ux_attrs);
+ if (get<0>(dar) || get<1>(dar)) {
+ update_fh(rgw_fh);
+ }
}
}
goto done;
return 0;
} /* RGWLibFS::setattr */
+ /* called under rgw_fh->mtx held */
+ void RGWLibFS::update_fh(RGWFileHandle *rgw_fh)
+ {
+ int rc, rc2;
+ string obj_name{rgw_fh->relative_object_name()};
+ buffer::list ux_key, ux_attrs;
+
+ if (rgw_fh->is_dir() &&
+ (likely(! rgw_fh->is_bucket()))) {
+ obj_name += "/";
+ }
+
+ lsubdout(get_context(), rgw, 17)
+ << __func__
+ << " update old versioned fh : " << obj_name
+ << dendl;
+
+ RGWSetAttrsRequest req(cct, get_user(), rgw_fh->bucket_name(), obj_name);
+
+ rgw_fh->encode_attrs(ux_key, ux_attrs);
+
+ req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
+ req.emplace_attr(RGW_ATTR_UNIX1, std::move(ux_attrs));
+
+ rc = rgwlib.get_fe()->execute_req(&req);
+ rc2 = req.get_ret();
+
+ if ((rc != 0) || (rc2 != 0)) {
+ lsubdout(get_context(), rgw, 17)
+ << __func__
+ << " update fh failed : " << obj_name
+ << dendl;
+ }
+ } /* RGWLibFS::update_fh */
+
void RGWLibFS::close()
{
state.flags |= FLAG_CLOSED;
{
RGWLibFS* fs;
public:
- ObjUnref(RGWLibFS* fs) : fs(fs) {}
+ ObjUnref(RGWLibFS* _fs) : fs(_fs) {}
void operator()(RGWFileHandle* fh) const {
lsubdout(fs->get_context(), rgw, 5)
<< __func__
= get_context()->_conf->rgw_nfs_namespace_expire_secs;
/* max events to gc in one cycle */
- uint32_t max_ev =
- std::max(1, get_context()->_conf->rgw_nfs_max_gc);
+ uint32_t max_ev = get_context()->_conf->rgw_nfs_max_gc;
struct timespec now, expire_ts;
event_vector ve;
}
RGWFileHandle::~RGWFileHandle() {
- /* in the non-delete case, handle may still be in handle table */
- if (fh_hook.is_linked()) {
- fs->fh_cache.remove(fh.fh_hk.object, this, FHCache::FLAG_LOCK);
- }
/* cond-unref parent */
- if (parent && (! parent->is_root())) {
+ if (parent && (! parent->is_mount())) {
/* safe because if parent->unref causes its deletion,
* there are a) by refcnt, no other objects/paths pointing
* to it and b) by the semantics of valid iteration of
rgw::encode(*this, ux_attrs1);
} /* RGWFileHandle::encode_attrs */
- void RGWFileHandle::decode_attrs(const ceph::buffer::list* ux_key1,
- const ceph::buffer::list* ux_attrs1)
+ DecodeAttrsResult RGWFileHandle::decode_attrs(const ceph::buffer::list* ux_key1,
+ const ceph::buffer::list* ux_attrs1)
{
+ DecodeAttrsResult dar { false, false };
fh_key fhk;
auto bl_iter_key1 = const_cast<buffer::list*>(ux_key1)->begin();
rgw::decode(fhk, bl_iter_key1);
- assert(this->fh.fh_hk == fhk.fh_hk);
+ if (fhk.version >= 2) {
+ assert(this->fh.fh_hk == fhk.fh_hk);
+ } else {
+ get<0>(dar) = true;
+ }
auto bl_iter_unix1 = const_cast<buffer::list*>(ux_attrs1)->begin();
rgw::decode(*this, bl_iter_unix1);
+ if (this->state.version < 2) {
+ get<1>(dar) = true;
+ }
+
+ return dar;
} /* RGWFileHandle::decode_attrs */
bool RGWFileHandle::reclaim() {
lsubdout(fs->get_context(), rgw, 17)
<< __func__ << " " << *this
<< dendl;
- /* remove if still in fh_cache */
+ /* in the non-delete case, handle may still be in handle table */
if (fh_hook.is_linked()) {
- fs->fh_cache.remove(fh.fh_hk.object, this, FHCache::FLAG_LOCK);
+ /* in this case, we are being called from a context which holds
+ * the partition lock */
+ fs->fh_cache.remove(fh.fh_hk.object, this, FHCache::FLAG_NONE);
}
return true;
} /* RGWFileHandle::reclaim */
return false;
}
- int RGWFileHandle::readdir(rgw_readdir_cb rcb, void *cb_arg, uint64_t *offset,
+ std::ostream& operator<<(std::ostream &os,
+ RGWFileHandle::readdir_offset const &offset)
+ {
+ using boost::get;
+ if (unlikely(!! get<uint64_t*>(&offset))) {
+ uint64_t* ioff = get<uint64_t*>(offset);
+ os << *ioff;
+ }
+ else
+ os << get<const char*>(offset);
+ return os;
+ }
+
+ int RGWFileHandle::readdir(rgw_readdir_cb rcb, void *cb_arg,
+ readdir_offset offset,
bool *eof, uint32_t flags)
{
using event = RGWLibFS::event;
+ using boost::get;
int rc = 0;
struct timespec now;
CephContext* cct = fs->get_context();
- if ((*offset == 0) &&
- (flags & RGW_READDIR_FLAG_DOTDOT)) {
- /* send '.' and '..' with their NFS-defined offsets */
- rcb(".", cb_arg, 1, RGW_LOOKUP_FLAG_DIR);
- rcb("..", cb_arg, 2, RGW_LOOKUP_FLAG_DIR);
- }
-
- lsubdout(fs->get_context(), rgw, 15)
- << __func__
- << " offset=" << *offset
- << dendl;
-
directory* d = get<directory>(&variant_type);
if (d) {
(void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
d->last_readdir = now;
}
+ bool initial_off;
+ if (likely(!! get<const char*>(&offset))) {
+ initial_off = ! get<const char*>(offset);
+ } else {
+ initial_off = (*get<uint64_t*>(offset) == 0);
+ }
+
if (is_root()) {
RGWListBucketsRequest req(cct, fs->get_user(), this, rcb, cb_arg,
offset);
(void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
lock_guard guard(mtx);
state.atime = now;
- if (*offset == 0)
+ if (initial_off)
set_nlink(2);
inc_nlink(req.d_count);
*eof = req.eof();
(void) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* !LOCKED */
lock_guard guard(mtx);
state.atime = now;
- if (*offset == 0)
+ if (initial_off)
set_nlink(2);
inc_nlink(req.d_count);
*eof = req.eof();
}
}
+ int overlap = 0;
+ if ((static_cast<off_t>(off) < f->write_req->real_ofs) &&
+ ((f->write_req->real_ofs - off) <= len)) {
+ overlap = f->write_req->real_ofs - off;
+ off = f->write_req->real_ofs;
+ buffer = static_cast<char*>(buffer) + overlap;
+ len -= overlap;
+ }
+
buffer::list bl;
/* XXXX */
#if 0
rc = -EIO;
}
- *bytes_written = (rc == 0) ? len : 0;
+ *bytes_written = (rc == 0) ? (len + overlap) : 0;
return rc;
} /* RGWFileHandle::write */
int RGWWriteRequest::exec_start() {
struct req_state* s = get_state();
+ auto compression_type =
+ get_store()->get_zone_params().get_compression_type(
+ s->bucket_info.placement_rule);
+
/* not obviously supportable */
assert(! dlo_manifest);
assert(! slo_info);
processor = select_processor(*static_cast<RGWObjectCtx *>(s->obj_ctx),
&multipart);
op_ret = processor->prepare(get_store(), NULL);
+ if (op_ret < 0) {
+ ldout(s->cct, 20) << "processor->prepare() returned ret=" << op_ret
+ << dendl;
+ goto done;
+ }
+
+ filter = processor;
+ if (compression_type != "none") {
+ plugin = Compressor::create(s->cct, compression_type);
+ if (! plugin) {
+ ldout(s->cct, 1) << "Cannot load plugin for rgw_compression_type "
+ << compression_type << dendl;
+ } else {
+ compressor.emplace(s->cct, plugin, filter);
+ filter = &*compressor;
+ }
+ }
done:
return op_ret;
orig_data = data;
}
hash.Update((const byte *)data.c_str(), data.length());
- op_ret = put_data_and_throttle(processor, data, ofs,
- need_to_wait);
+ op_ret = put_data_and_throttle(filter, data, ofs, need_to_wait);
if (op_ret < 0) {
if (!need_to_wait || op_ret != -EEXIST) {
ldout(s->cct, 20) << "processor->thottle_data() returned ret="
dispose_processor(processor);
processor = select_processor(*static_cast<RGWObjectCtx *>(s->obj_ctx),
&multipart);
+ filter = processor;
string oid_rand;
char buf[33];
goto done;
}
- op_ret = put_data_and_throttle(processor, data, ofs, false);
+ /* restore compression filter, if any */
+ if (compressor) {
+ compressor.emplace(s->cct, plugin, filter);
+ filter = &*compressor;
+ }
+
+ op_ret = put_data_and_throttle(filter, data, ofs, false);
if (op_ret < 0) {
goto done;
}
struct timespec omtime = rgw_fh->get_mtime();
real_time appx_t = real_clock::now();
- s->obj_size = ofs; // XXX check ofs
+ s->obj_size = bytes_written;
perfcounter->inc(l_rgw_put_b, s->obj_size);
op_ret = get_store()->check_quota(s->bucket_owner.get_id(), s->bucket,
goto done;
}
- op_ret = get_store()->check_bucket_shards(s->bucket_info, s->bucket, bucket_quota);
+ op_ret = get_store()->check_bucket_shards(s->bucket_info, s->bucket,
+ bucket_quota);
if (op_ret < 0) {
goto done;
}
hash.Final(m);
+ if (compressor && compressor->is_compressed()) {
+ bufferlist tmp;
+ RGWCompressionInfo cs_info;
+ cs_info.compression_type = plugin->get_type_name();
+ cs_info.orig_size = s->obj_size;
+ cs_info.blocks = std::move(compressor->get_compression_blocks());
+ ::encode(cs_info, tmp);
+ attrs[RGW_ATTR_COMPRESSION] = tmp;
+ ldout(s->cct, 20) << "storing " << RGW_ATTR_COMPRESSION
+ << " with type=" << cs_info.compression_type
+ << ", orig_size=" << cs_info.orig_size
+ << ", blocks=" << cs_info.blocks.size() << dendl;
+ }
+
buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5);
etag = calc_md5;
attrbl.append(val.c_str(), val.size() + 1);
}
- rgw_get_request_metadata(s->cct, s->info, attrs);
+ op_ret = rgw_get_request_metadata(s->cct, s->info, attrs);
+ if (op_ret < 0) {
+ goto done;
+ }
encode_delete_at_attr(delete_at, attrs);
/* Add a custom metadata to expose the information whether an object
/* stash access data for "mount" */
RGWLibFS* new_fs = new RGWLibFS(static_cast<CephContext*>(rgw), uid, acc_key,
- sec_key);
+ sec_key, "/");
+ assert(new_fs);
+
+ rc = new_fs->authorize(rgwlib.get_store());
+ if (rc != 0) {
+ delete new_fs;
+ return -EINVAL;
+ }
+
+ /* register fs for shared gc */
+ rgwlib.get_fe()->get_process()->register_fs(new_fs);
+
+ struct rgw_fs *fs = new_fs->get_fs();
+ fs->rgw = rgw;
+
+ /* XXX we no longer assume "/" is unique, but we aren't tracking the
+ * roots atm */
+
+ *rgw_fs = fs;
+
+ return 0;
+}
+
+int rgw_mount2(librgw_t rgw, const char *uid, const char *acc_key,
+ const char *sec_key, const char *root, struct rgw_fs **rgw_fs,
+ uint32_t flags)
+{
+ int rc = 0;
+
+ /* stash access data for "mount" */
+ RGWLibFS* new_fs = new RGWLibFS(static_cast<CephContext*>(rgw), uid, acc_key,
+ sec_key, root);
assert(new_fs);
rc = new_fs->authorize(rgwlib.get_store());
vfs_st->f_bavail = UINT64_MAX;
vfs_st->f_files = 1024; /* object count, do we have an est? */
vfs_st->f_ffree = UINT64_MAX;
- vfs_st->f_fsid[0] = fs->get_inst();
- vfs_st->f_fsid[1] = fs->get_inst();
+ vfs_st->f_fsid[0] = fs->get_fsid();
+ vfs_st->f_fsid[1] = fs->get_fsid();
vfs_st->f_flag = 0;
vfs_st->f_namemax = 4096;
return 0;
return -ENOENT;
}
} else {
- /* lookup in a readdir callback */
- enum rgw_fh_type fh_type = fh_type_of(flags);
-
- uint32_t sl_flags = (flags & RGW_LOOKUP_FLAG_RCB)
- ? RGWFileHandle::FLAG_NONE
- : RGWFileHandle::FLAG_EXACT_MATCH;
-
- fhr = fs->stat_leaf(parent, path, fh_type, sl_flags);
- if (! get<0>(fhr)) {
- if (! (flags & RGW_LOOKUP_FLAG_CREATE))
- return -ENOENT;
- else
- fhr = fs->lookup_fh(parent, path, RGWFileHandle::FLAG_CREATE);
+ /* special: after readdir--note extra ref()! */
+ if (unlikely((strcmp(path, "..") == 0))) {
+ rgw_fh = parent;
+ lsubdout(fs->get_context(), rgw, 17)
+ << __func__ << "BANG"<< *rgw_fh
+ << dendl;
+ fs->ref(rgw_fh);
+ } else {
+ /* lookup in a readdir callback */
+ enum rgw_fh_type fh_type = fh_type_of(flags);
+
+ uint32_t sl_flags = (flags & RGW_LOOKUP_FLAG_RCB)
+ ? RGWFileHandle::FLAG_NONE
+ : RGWFileHandle::FLAG_EXACT_MATCH;
+
+ fhr = fs->stat_leaf(parent, path, fh_type, sl_flags);
+ if (! get<0>(fhr)) {
+ if (! (flags & RGW_LOOKUP_FLAG_CREATE))
+ return -ENOENT;
+ else
+ fhr = fs->lookup_fh(parent, path, RGWFileHandle::FLAG_CREATE);
+ }
+ rgw_fh = get<0>(fhr);
}
- rgw_fh = get<0>(fhr);
} /* !root */
struct rgw_file_handle *rfh = rgw_fh->get_fh();
/* bad parent */
return -EINVAL;
}
+
+ lsubdout(parent->get_fs()->get_context(), rgw, 15)
+ << __func__
+ << " offset=" << *offset
+ << dendl;
+
+ if ((*offset == 0) &&
+ (flags & RGW_READDIR_FLAG_DOTDOT)) {
+ /* send '.' and '..' with their NFS-defined offsets */
+ rcb(".", cb_arg, 1, RGW_LOOKUP_FLAG_DIR);
+ rcb("..", cb_arg, 2, RGW_LOOKUP_FLAG_DIR);
+ }
+
int rc = parent->readdir(rcb, cb_arg, offset, eof, flags);
return rc;
+} /* rgw_readdir */
+
+/* enumeration continuing from name */
+int rgw_readdir2(struct rgw_fs *rgw_fs,
+ struct rgw_file_handle *parent_fh, const char *name,
+ rgw_readdir_cb rcb, void *cb_arg, bool *eof,
+ uint32_t flags)
+{
+ RGWFileHandle* parent = get_rgwfh(parent_fh);
+ if (! parent) {
+ /* bad parent */
+ return -EINVAL;
+ }
+
+ lsubdout(parent->get_fs()->get_context(), rgw, 15)
+ << __func__
+ << " offset=" << ((name) ? name : "(nil)")
+ << dendl;
+
+ if ((! name) &&
+ (flags & RGW_READDIR_FLAG_DOTDOT)) {
+ /* send '.' and '..' with their NFS-defined offsets */
+ rcb(".", cb_arg, 1, RGW_LOOKUP_FLAG_DIR);
+ rcb("..", cb_arg, 2, RGW_LOOKUP_FLAG_DIR);
+ }
+
+ int rc = parent->readdir(rcb, cb_arg, name, eof, flags);
+ return rc;
+} /* rgw_readdir2 */
+
+/* project offset of dirent name */
+int rgw_dirent_offset(struct rgw_fs *rgw_fs,
+ struct rgw_file_handle *parent_fh,
+ const char *name, int64_t *offset,
+ uint32_t flags)
+{
+ RGWFileHandle* parent = get_rgwfh(parent_fh);
+ if ((! parent)) {
+ /* bad parent */
+ return -EINVAL;
+ }
+ std::string sname{name};
+ int rc = parent->offset_of(sname, offset, flags);
+ return rc;
}
/*
if (! rgw_fh->is_file())
return -EISDIR;
- if (! rgw_fh->is_open())
- return -EPERM;
+ if (! rgw_fh->is_open()) {
+ if (flags & RGW_OPEN_FLAG_V3) {
+ rc = rgw_fh->open(flags);
+ if (!! rc)
+ return rc;
+ } else
+ return -EPERM;
+ }
rc = rgw_fh->write(offset, length, bytes_written, buffer);