Skip to content

Commit b8954e5

Browse files
author
Zhi Zhang
committed
client: optimize rename operation under different quota root
It took very long time to move a large directory to another directory under different quota root, because rename operation was switched to copy and unlink operations, even if the destination directory didn't enable quota or had enough room for source directory. Fixes: http://tracker.ceph.com/issues/39715 Signed-off-by: Zhi Zhang <zhangz.david@outlook.com>
1 parent 9068510 commit b8954e5

1 file changed

Lines changed: 59 additions & 10 deletions

File tree

src/client/Client.cc

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12624,15 +12624,6 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch
1262412624
else
1262512625
return -EROFS;
1262612626
}
12627-
if (fromdir != todir) {
12628-
Inode *fromdir_root =
12629-
fromdir->quota.is_enable() ? fromdir : get_quota_root(fromdir, perm);
12630-
Inode *todir_root =
12631-
todir->quota.is_enable() ? todir : get_quota_root(todir, perm);
12632-
if (fromdir_root != todir_root) {
12633-
return -EXDEV;
12634-
}
12635-
}
1263612627

1263712628
InodeRef target;
1263812629
MetaRequest *req = new MetaRequest(op);
@@ -12665,7 +12656,32 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch
1266512656
req->dentry_unless = CEPH_CAP_FILE_EXCL;
1266612657

1266712658
InodeRef oldin, otherin;
12668-
res = _lookup(fromdir, fromname, 0, &oldin, perm);
12659+
Inode *fromdir_root = nullptr;
12660+
Inode *todir_root = nullptr;
12661+
int mask = 0;
12662+
bool quota_check = false;
12663+
if (fromdir != todir) {
12664+
fromdir_root =
12665+
fromdir->quota.is_enable() ? fromdir : get_quota_root(fromdir, perm);
12666+
todir_root =
12667+
todir->quota.is_enable() ? todir : get_quota_root(todir, perm);
12668+
12669+
if (todir_root->quota.is_enable() && fromdir_root != todir_root) {
12670+
// use CEPH_STAT_RSTAT mask to force send getattr or lookup request
12671+
// to auth MDS to get latest rstat for todir_root and source dir
12672+
// even if their dentry caches and inode caps are satisfied.
12673+
res = _getattr(todir_root, CEPH_STAT_RSTAT, perm, true);
12674+
if (res < 0)
12675+
goto fail;
12676+
12677+
quota_check = true;
12678+
if (oldde->inode && oldde->inode->is_dir()) {
12679+
mask |= CEPH_STAT_RSTAT;
12680+
}
12681+
}
12682+
}
12683+
12684+
res = _lookup(fromdir, fromname, mask, &oldin, perm);
1266912685
if (res < 0)
1267012686
goto fail;
1267112687

@@ -12674,6 +12690,39 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch
1267412690
req->set_old_inode(oldinode);
1267512691
req->old_inode_drop = CEPH_CAP_LINK_SHARED;
1267612692

12693+
if (quota_check) {
12694+
int64_t old_bytes, old_files;
12695+
if (oldinode->is_dir()) {
12696+
old_bytes = oldinode->rstat.rbytes;
12697+
old_files = oldinode->rstat.rsize();
12698+
} else {
12699+
old_bytes = oldinode->size;
12700+
old_files = 1;
12701+
}
12702+
12703+
bool quota_exceed = false;
12704+
if (todir_root && todir_root->quota.max_bytes &&
12705+
(old_bytes + todir_root->rstat.rbytes) >= todir_root->quota.max_bytes) {
12706+
ldout(cct, 10) << "_rename (" << oldinode->ino << " bytes="
12707+
<< old_bytes << ") to (" << todir->ino
12708+
<< ") will exceed quota on " << *todir_root << dendl;
12709+
quota_exceed = true;
12710+
}
12711+
12712+
if (todir_root && todir_root->quota.max_files &&
12713+
(old_files + todir_root->rstat.rsize()) >= todir_root->quota.max_files) {
12714+
ldout(cct, 10) << "_rename (" << oldinode->ino << " files="
12715+
<< old_files << ") to (" << todir->ino
12716+
<< ") will exceed quota on " << *todir_root << dendl;
12717+
quota_exceed = true;
12718+
}
12719+
12720+
if (quota_exceed) {
12721+
res = (oldinode->is_dir()) ? -EXDEV : -EDQUOT;
12722+
goto fail;
12723+
}
12724+
}
12725+
1267712726
res = _lookup(todir, toname, 0, &otherin, perm);
1267812727
switch (res) {
1267912728
case 0:

0 commit comments

Comments
 (0)