Inode *diri = dir->parent_inode;
clear_dir_complete_and_ordered(diri, false);
dn = link(dir, dname, in, dn);
+
+ if (old_dentry) {
+ dn->is_renaming = false;
+ signal_cond_list(waiting_for_rename);
+ }
}
update_dentry_lease(dn, dlease, from, session);
}
int Client::_lookup(Inode *dir, const string& dname, int mask, InodeRef *target,
- const UserPerm& perms, std::string* alternate_name)
+ const UserPerm& perms, std::string* alternate_name,
+ bool is_rename)
{
int r = 0;
Dentry *dn = NULL;
} else {
ldout(cct, 20) << " no cap on " << dn->inode->vino() << dendl;
}
+
+ // In rare case during the rename if another thread tries to
+ // lookup the dst dentry, it may get an inconsistent result
+ // that both src dentry and dst dentry will link to the same
+ // inode at the same time.
+ // Will wait the rename to finish and try it again.
+ if (!is_rename && dn->is_renaming) {
+ ldout(cct, 1) << __func__ << " dir " << *dir
+ << " rename is on the way, will wait for dn '"
+ << dname << "'" << dendl;
+ wait_on_list(waiting_for_rename);
+ goto relookup;
+ }
} else {
// can we conclude ENOENT locally?
if (dir->caps_issued_mask(CEPH_CAP_FILE_SHARED, true) &&
req->old_dentry_drop = CEPH_CAP_FILE_SHARED;
req->old_dentry_unless = CEPH_CAP_FILE_EXCL;
+ de->is_renaming = true;
req->set_dentry(de);
req->dentry_drop = CEPH_CAP_FILE_SHARED;
req->dentry_unless = CEPH_CAP_FILE_EXCL;
InodeRef oldin, otherin;
- res = _lookup(fromdir, fromname, 0, &oldin, perm);
+ res = _lookup(fromdir, fromname, 0, &oldin, perm, nullptr, true);
if (res < 0)
goto fail;
req->set_old_inode(oldinode);
req->old_inode_drop = CEPH_CAP_LINK_SHARED;
- res = _lookup(todir, toname, 0, &otherin, perm);
+ res = _lookup(todir, toname, 0, &otherin, perm, nullptr, true);
switch (res) {
case 0:
{
res = make_request(req, perm, &target);
ldout(cct, 10) << "rename result is " << res << dendl;
+ // if rename fails it will miss waking up the waiters
+ if (op == CEPH_MDS_OP_RENAME && de->is_renaming) {
+ de->is_renaming = false;
+ signal_cond_list(waiting_for_rename);
+ }
+
// renamed item from our cache
trim_cache();
const UserPerm& perms);
int _lookup(Inode *dir, const std::string& dname, int mask, InodeRef *target,
- const UserPerm& perm, std::string* alternate_name=nullptr);
+ const UserPerm& perm, std::string* alternate_name=nullptr,
+ bool is_rename=false);
int _link(Inode *in, Inode *dir, const char *name, const UserPerm& perm, std::string alternate_name,
InodeRef *inp = 0);
std::map<std::pair<int64_t,std::string>, int> pool_perms;
std::list<ceph::condition_variable*> waiting_for_pool_perm;
+ std::list<ceph::condition_variable*> waiting_for_rename;
+
uint64_t retries_on_invalidate = 0;
// state reclaim