@@ -596,21 +596,25 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
596596{
597597 struct dentry * upperdir = ovl_dentry_upper (dentry -> d_parent );
598598 struct inode * dir = upperdir -> d_inode ;
599- struct dentry * upper = ovl_dentry_upper ( dentry ) ;
599+ struct dentry * upper ;
600600 int err ;
601601
602602 inode_lock_nested (dir , I_MUTEX_PARENT );
603+ upper = lookup_one_len (dentry -> d_name .name , upperdir ,
604+ dentry -> d_name .len );
605+ err = PTR_ERR (upper );
606+ if (IS_ERR (upper ))
607+ goto out_unlock ;
608+
603609 err = - ESTALE ;
604- if (upper -> d_parent == upperdir ) {
605- /* Don't let d_delete() think it can reset d_inode */
606- dget (upper );
610+ if (upper == ovl_dentry_upper (dentry )) {
607611 if (is_dir )
608612 err = vfs_rmdir (dir , upper );
609613 else
610614 err = vfs_unlink (dir , upper , NULL );
611- dput (upper );
612615 ovl_dentry_version_inc (dentry -> d_parent );
613616 }
617+ dput (upper );
614618
615619 /*
616620 * Keeping this dentry hashed would mean having to release
@@ -620,6 +624,7 @@ static int ovl_remove_upper(struct dentry *dentry, bool is_dir)
620624 */
621625 if (!err )
622626 d_drop (dentry );
627+ out_unlock :
623628 inode_unlock (dir );
624629
625630 return err ;
@@ -840,29 +845,39 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
840845
841846 trap = lock_rename (new_upperdir , old_upperdir );
842847
843- olddentry = ovl_dentry_upper (old );
844- newdentry = ovl_dentry_upper (new );
845- if (newdentry ) {
848+
849+ olddentry = lookup_one_len (old -> d_name .name , old_upperdir ,
850+ old -> d_name .len );
851+ err = PTR_ERR (olddentry );
852+ if (IS_ERR (olddentry ))
853+ goto out_unlock ;
854+
855+ err = - ESTALE ;
856+ if (olddentry != ovl_dentry_upper (old ))
857+ goto out_dput_old ;
858+
859+ newdentry = lookup_one_len (new -> d_name .name , new_upperdir ,
860+ new -> d_name .len );
861+ err = PTR_ERR (newdentry );
862+ if (IS_ERR (newdentry ))
863+ goto out_dput_old ;
864+
865+ err = - ESTALE ;
866+ if (ovl_dentry_upper (new )) {
846867 if (opaquedir ) {
847- newdentry = opaquedir ;
848- opaquedir = NULL ;
868+ if ( newdentry ! = opaquedir )
869+ goto out_dput ;
849870 } else {
850- dget (newdentry );
871+ if (newdentry != ovl_dentry_upper (new ))
872+ goto out_dput ;
851873 }
852874 } else {
853875 new_create = true;
854- newdentry = lookup_one_len (new -> d_name .name , new_upperdir ,
855- new -> d_name .len );
856- err = PTR_ERR (newdentry );
857- if (IS_ERR (newdentry ))
858- goto out_unlock ;
876+ if (!d_is_negative (newdentry ) &&
877+ (!new_opaque || !ovl_is_whiteout (newdentry )))
878+ goto out_dput ;
859879 }
860880
861- err = - ESTALE ;
862- if (olddentry -> d_parent != old_upperdir )
863- goto out_dput ;
864- if (newdentry -> d_parent != new_upperdir )
865- goto out_dput ;
866881 if (olddentry == trap )
867882 goto out_dput ;
868883 if (newdentry == trap )
@@ -925,6 +940,8 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
925940
926941out_dput :
927942 dput (newdentry );
943+ out_dput_old :
944+ dput (olddentry );
928945out_unlock :
929946 unlock_rename (new_upperdir , old_upperdir );
930947out_revert_creds :
0 commit comments