@@ -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