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)) {
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()) {
+ /* a bucket may have an object storing Unix attributes, check
+ * for and delete it */
+ LookupFHResult fhr;
+ fhr = stat_bucket(parent, name, bs, RGWFileHandle::FLAG_LOCKED);
+ 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 extra ref */
+ 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);
+ }
+
/* XXXX remove uri and deal with bucket and object names */
string uri = "/";
uri += name;
(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;
static constexpr uint32_t FLAG_NONE = 0x0000;
static constexpr uint32_t FLAG_CLOSED = 0x0001;
+ struct BucketStats {
+ size_t size;
+ size_t size_rounded;
+ real_time creation_time;
+ uint64_t num_entries;
+ };
+
RGWLibFS(CephContext* _cct, const char *_uid, const char *_user_id,
const char* _key)
: cct(_cct), root_fh(this, new_inst()), invalidate_cb(nullptr),
LookupFHResult fhr { nullptr, uint32_t(RGWFileHandle::FLAG_NONE) };
RGWFileHandle::FHCache::Latch lat;
+ bool fh_locked = flags & RGWFileHandle::FLAG_LOCKED;
retry:
RGWFileHandle* fh =
RGWFileHandle::FHCache::FLAG_LOCK);
/* LATCHED */
if (fh) {
- fh->mtx.lock(); // XXX !RAII because may-return-LOCKED
+ if (likely(! fh_locked))
+ fh->mtx.lock(); // XXX !RAII because may-return-LOCKED
/* need initial ref from LRU (fast path) */
if (! fh_lru.ref(fh, cohort::lru::FLAG_INITIAL)) {
lat.lock->unlock();
- fh->mtx.unlock();
+ if (likely(! fh_locked))
+ fh->mtx.unlock();
goto retry; /* !LATCHED */
}
/* LATCHED, LOCKED */
return fhr;
RGWFileHandle::FHCache::Latch lat;
+ bool fh_locked = flags & RGWFileHandle::FLAG_LOCKED;
std::string obj_name{name};
std::string key_name{parent->make_key_name(name)};
RGWFileHandle::FHCache::FLAG_LOCK);
/* LATCHED */
if (fh) {
- fh->mtx.lock(); // XXX !RAII because may-return-LOCKED
+ if (likely(! fh_locked))
+ fh->mtx.lock(); // XXX !RAII because may-return-LOCKED
if (fh->flags & RGWFileHandle::FLAG_DELETED) {
/* for now, delay briefly and retry */
lat.lock->unlock();
- fh->mtx.unlock();
+ if (likely(! fh_locked))
+ fh->mtx.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
goto retry; /* !LATCHED */
}
/* need initial ref from LRU (fast path) */
if (! fh_lru.ref(fh, cohort::lru::FLAG_INITIAL)) {
lat.lock->unlock();
- fh->mtx.unlock();
+ if (likely(! fh_locked))
+ fh->mtx.unlock();
goto retry; /* !LATCHED */
}
/* LATCHED, LOCKED */
if (! (flags & RGWFileHandle::FLAG_LOCK))
- fh->mtx.unlock(); /* ! LOCKED */
+ if (likely(! fh_locked))
+ fh->mtx.unlock(); /* ! LOCKED */
} else {
/* make or re-use handle */
RGWFileHandle::Factory prototype(this, get_inst(), parent, fhk,
int setattr(RGWFileHandle* rgw_fh, struct stat* st, uint32_t mask,
uint32_t flags);
- LookupFHResult stat_bucket(RGWFileHandle* parent,
- const char *path, uint32_t flags);
+ LookupFHResult stat_bucket(RGWFileHandle* parent, const char *path,
+ RGWLibFS::BucketStats& bs,
+ uint32_t flags);
LookupFHResult stat_leaf(RGWFileHandle* parent, const char *path,
enum rgw_fh_type type = RGW_FS_TYPE_NIL,
public:
std::string uri;
std::map<std::string, buffer::list> attrs;
+ RGWLibFS::BucketStats& bs;
RGWStatBucketRequest(CephContext* _cct, RGWUserInfo *_user,
- const std::string& _path)
- : RGWLibRequest(_cct, _user) {
+ const std::string& _path,
+ RGWLibFS::BucketStats& _stats)
+ : RGWLibRequest(_cct, _user), bs(_stats) {
uri = "/" + _path;
op = this;
}
void send_response() override {
bucket.creation_time = get_state()->bucket_info.creation_time;
+ bs.size = bucket.size;
+ bs.size_rounded = bucket.size_rounded;
+ bs.creation_time = bucket.creation_time;
+ bs.num_entries = bucket.count;
std::swap(attrs, get_state()->bucket_attrs);
}