return 0;
}
- LookupFHResult RGWLibFS::stat_bucket(RGWFileHandle* parent,
- const char *path, uint32_t flags)
+ LookupFHResult RGWLibFS::stat_bucket(RGWFileHandle* parent, const char *path,
+ RGWLibFS::BucketStats& bs,
+ uint32_t flags)
{
LookupFHResult fhr{nullptr, 0};
std::string bucket_name{path};
- RGWStatBucketRequest req(cct, get_user(), bucket_name);
+ RGWStatBucketRequest req(cct, get_user(), bucket_name, bs);
int rc = rgwlib.get_fe()->execute_req(&req);
if ((rc == 0) &&
(req.get_ret() == 0) &&
(req.matched())) {
fhr = lookup_fh(parent, path,
+ (flags & RGWFileHandle::FLAG_LOCKED)|
RGWFileHandle::FLAG_CREATE|
RGWFileHandle::FLAG_BUCKET);
if (get<0>(fhr)) {
RGWFileHandle* rgw_fh = get<0>(fhr);
- lock_guard guard(rgw_fh->mtx);
+ if (! (flags & RGWFileHandle::FLAG_LOCKED)) {
+ rgw_fh->mtx.lock();
+ }
rgw_fh->set_times(req.get_ctime());
/* restore attributes */
auto ux_key = req.get_attr(RGW_ATTR_UNIX_KEY1);
if (ux_key && ux_attrs) {
rgw_fh->decode_attrs(ux_key, ux_attrs);
}
+ if (! (flags & RGWFileHandle::FLAG_LOCKED)) {
+ rgw_fh->mtx.unlock();
+ }
}
}
return fhr;
* mechanism to avoid this is to store leaf object names with an
* object locator w/o trailing slash */
- /* mutating path */
- std::string obj_path{parent->relative_object_name()};
- if ((obj_path.length() > 0) &&
- (obj_path.back() != '/'))
- obj_path += "/";
- obj_path += path;
+ std::string obj_path = parent->format_child_name(path, false);
for (auto ix : { 0, 1, 2 }) {
switch (ix) {
int RGWLibFS::unlink(RGWFileHandle* rgw_fh, const char* name, uint32_t flags)
{
int rc = 0;
+ BucketStats bs;
RGWFileHandle* parent = nullptr;
+ RGWFileHandle* bkt_fh = nullptr;
if (unlikely(flags & RGWFileHandle::FLAG_UNLINK_THIS)) {
/* LOCKED */
}
if (parent->is_root()) {
- /* XXXX remove uri and deal with bucket and object names */
- string uri = "/";
- uri += name;
- RGWDeleteBucketRequest req(cct, get_user(), uri);
+ /* a bucket may have an object storing Unix attributes, check
+ * for and delete it */
+ LookupFHResult fhr;
+ fhr = stat_bucket(parent, name, bs, (rgw_fh) ?
+ RGWFileHandle::FLAG_LOCKED :
+ RGWFileHandle::FLAG_NONE);
+ bkt_fh = get<0>(fhr);
+ if (unlikely(! bkt_fh)) {
+ /* implies !rgw_fh, so also !LOCKED */
+ return -ENOENT;
+ }
+
+ if (bs.num_entries > 1) {
+ unref(bkt_fh); /* return stat_bucket ref */
+ if (likely(!! rgw_fh)) { /* return lock and ref from
+ * lookup_fh (or caller in the
+ * special case of
+ * RGWFileHandle::FLAG_UNLINK_THIS) */
+ rgw_fh->mtx.unlock();
+ unref(rgw_fh);
+ }
+ return -ENOTEMPTY;
+ } else {
+ /* delete object w/key "<bucket>/" (uxattrs), if any */
+ string oname{"/"};
+ RGWDeleteObjRequest req(cct, get_user(), bkt_fh->bucket_name(), oname);
+ rc = rgwlib.get_fe()->execute_req(&req);
+ /* don't care if ENOENT */
+ unref(bkt_fh);
+ }
+
+ string bname{name};
+ RGWDeleteBucketRequest req(cct, get_user(), bname);
rc = rgwlib.get_fe()->execute_req(&req);
if (! rc) {
rc = req.get_ret();
}
}
- rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
- fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh,
- RGWFileHandle::FHCache::FLAG_LOCK);
-
-#if 1 /* XXX verify clear cache */
- fh_key fhk(rgw_fh->fh.fh_hk);
- LookupFHResult tfhr = lookup_fh(fhk, RGWFileHandle::FLAG_LOCKED);
- RGWFileHandle* nfh = get<0>(tfhr);
- assert(!nfh);
-#endif
+ /* ENOENT when raced with other s3 gateway */
+ if (! rc || rc == -ENOENT) {
+ rgw_fh->flags |= RGWFileHandle::FLAG_DELETED;
+ fh_cache.remove(rgw_fh->fh.fh_hk.object, rgw_fh,
+ RGWFileHandle::FHCache::FLAG_LOCK);
+ }
if (! rc) {
real_time t = real_clock::now();
MkObjResult RGWLibFS::mkdir(RGWFileHandle* parent, const char *name,
struct stat *st, uint32_t mask, uint32_t flags)
{
- MkObjResult mkr{nullptr, -EINVAL};
int rc, rc2;
+ rgw_file_handle *lfh;
+
+ rc = rgw_lookup(get_fs(), parent->get_fh(), name, &lfh,
+ RGW_LOOKUP_FLAG_NONE);
+ if (! rc) {
+ /* conflict! */
+ rc = rgw_fh_rele(get_fs(), lfh, RGW_FH_RELE_FLAG_NONE);
+ return MkObjResult{nullptr, -EEXIST};
+ }
+ MkObjResult mkr{nullptr, -EINVAL};
LookupFHResult fhr;
RGWFileHandle* rgw_fh = nullptr;
buffer::list ux_key, ux_attrs;
return mkr;
}
- string uri = "/" + bname; /* XXX get rid of URI some day soon */
- RGWCreateBucketRequest req(get_context(), get_user(), uri);
+ RGWCreateBucketRequest req(get_context(), get_user(), bname);
/* save attrs */
req.emplace_attr(RGW_ATTR_UNIX_KEY1, std::move(ux_key));
} else {
/* create an object representing the directory */
buffer::list bl;
- string dir_name = /* XXX get rid of this some day soon, too */
- parent->relative_object_name();
-
- /* creating objects w/leading '/' makes a mess */
- if ((dir_name.size() > 0) &&
- (dir_name.back() != '/'))
- dir_name += "/";
- dir_name += name;
- dir_name += "/";
+ string dir_name = parent->format_child_name(name, true);
/* need valid S3 name (characters, length <= 1024, etc) */
rc = valid_fs_object_name(dir_name);
}
/* expand and check name */
- std::string obj_name{parent->relative_object_name()};
- if ((obj_name.size() > 0) &&
- (obj_name.back() != '/'))
- obj_name += "/";
- obj_name += name;
+ std::string obj_name = parent->format_child_name(name, false);
rc = valid_fs_object_name(obj_name);
if (rc != 0) {
return MkObjResult{nullptr, rc};
string obj_name{rgw_fh->relative_object_name()};
- if (rgw_fh->is_dir()) {
+ if (rgw_fh->is_dir() &&
+ (likely(! rgw_fh->is_bucket()))) {
obj_name += "/";
}
<< fh->name
<< " before ObjUnref refs=" << fh->get_refcnt()
<< dendl;
- fs->fh_lru.unref(fh, cohort::lru::FLAG_NONE);
+ fs->unref(fh);
}
};
* no unsafe iterators reaching it either--n.b., this constraint
* is binding oncode which may in future attempt to e.g.,
* cause the eviction of objects in LRU order */
- (void) get_fs()->fh_lru.unref(parent, cohort::lru::FLAG_NONE);
+ (void) get_fs()->unref(parent);
}
}
inc_nlink(req.d_count);
*eof = req.eof();
event ev(event::type::READDIR, get_key(), state.atime);
+ lock_guard sguard(fs->state.mtx);
fs->state.push_event(ev);
}
} else {
inc_nlink(req.d_count);
*eof = req.eof();
event ev(event::type::READDIR, get_key(), state.atime);
+ lock_guard sguard(fs->state.mtx);
fs->state.push_event(ev);
}
}
int rc = write_finish(FLAG_LOCKED);
flags &= ~FLAG_OPEN;
+ flags &= ~FLAG_STATELESS_OPEN;
+
return rc;
} /* RGWFileHandle::close */
goto done;
}
+ op_ret = get_store()->check_bucket_shards(s->bucket_info, s->bucket, bucket_quota);
+ if (op_ret < 0) {
+ goto done;
+ }
+
hash.Final(m);
buf_to_hex(m, CEPH_CRYPTO_MD5_DIGESTSIZE, calc_md5);
{
RGWLibFS *fs = static_cast<RGWLibFS*>(rgw_fs->fs_private);
fs->close();
- fs->rele();
return 0;
}
(strcmp(path, "/") == 0))) {
rgw_fh = parent;
} else {
- fhr = fs->stat_bucket(parent, path, RGWFileHandle::FLAG_NONE);
+ RGWLibFS::BucketStats bstat;
+ fhr = fs->stat_bucket(parent, path, bstat, RGWFileHandle::FLAG_NONE);
rgw_fh = get<0>(fhr);
if (! rgw_fh)
return -ENOENT;