X-Git-Url: https://git.karo-electronics.de/?p=karo-tx-linux.git;a=blobdiff_plain;f=fs%2Fnamei.c;h=f892ef9b3ead08b6ffea75833349d58d889e42c6;hp=caa28051e197e898e3c2bc52afce37bcbb284853;hb=25691330eb62649401cfb18ef518983511f6412f;hpb=f7d097973e8a9cd243fc86a271b35a04a6b255c5 diff --git a/fs/namei.c b/fs/namei.c index caa28051e197..f892ef9b3ead 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -3548,6 +3548,20 @@ void dentry_unhash(struct dentry *dentry) spin_unlock(&dentry->d_lock); } +static bool covered(struct vfsmount *mnt, struct dentry *dentry) +{ + /* test to see if a dentry is covered with a mount in + * the current mount namespace. + */ + bool is_covered; + + rcu_read_lock(); + is_covered = d_mountpoint(dentry) && __lookup_mnt(mnt, dentry, 1); + rcu_read_unlock(); + + return is_covered; +} + int vfs_rmdir(struct inode *dir, struct dentry *dentry) { int error = may_delete(dir, dentry, 1); @@ -3561,10 +3575,6 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) dget(dentry); mutex_lock(&dentry->d_inode->i_mutex); - error = -EBUSY; - if (d_mountpoint(dentry)) - goto out; - error = security_inode_rmdir(dir, dentry); if (error) goto out; @@ -3576,6 +3586,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) dentry->d_inode->i_flags |= S_DEAD; dont_mount(dentry); + detach_mounts(dentry); out: mutex_unlock(&dentry->d_inode->i_mutex); @@ -3623,6 +3634,9 @@ retry: error = -ENOENT; goto exit3; } + error = -EBUSY; + if (covered(nd.path.mnt, dentry)) + goto exit3; error = security_path_rmdir(&nd.path, dentry); if (error) goto exit3; @@ -3658,14 +3672,12 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) return -EPERM; mutex_lock(&dentry->d_inode->i_mutex); - if (d_mountpoint(dentry)) - error = -EBUSY; - else { - error = security_inode_unlink(dir, dentry); + error = security_inode_unlink(dir, dentry); + if (!error) { + error = dir->i_op->unlink(dir, dentry); if (!error) { - error = dir->i_op->unlink(dir, dentry); - if (!error) - dont_mount(dentry); + dont_mount(dentry); + detach_mounts(dentry); } } mutex_unlock(&dentry->d_inode->i_mutex); @@ -3717,6 +3729,9 @@ retry: inode = dentry->d_inode; if (!inode) goto slashes; + error = -EBUSY; + if (covered(nd.path.mnt, dentry)) + goto exit2; ihold(inode); error = security_path_unlink(&nd.path, dentry); if (error) @@ -3989,10 +4004,6 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, if (target) mutex_lock(&target->i_mutex); - error = -EBUSY; - if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry)) - goto out; - error = -EMLINK; if (max_links && !target && new_dir != old_dir && new_dir->i_nlink >= max_links) @@ -4007,6 +4018,7 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, if (target) { target->i_flags |= S_DEAD; dont_mount(new_dentry); + detach_mounts(new_dentry); } out: if (target) @@ -4032,16 +4044,14 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, if (target) mutex_lock(&target->i_mutex); - error = -EBUSY; - if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) - goto out; - error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); if (error) goto out; - if (target) + if (target) { dont_mount(new_dentry); + detach_mounts(new_dentry); + } if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) d_move(old_dentry, new_dentry); out: @@ -4165,6 +4175,11 @@ retry: error = -ENOTEMPTY; if (new_dentry == trap) goto exit5; + error = -EBUSY; + if (covered(oldnd.path.mnt, old_dentry)) + goto exit5; + if (covered(newnd.path.mnt, new_dentry)) + goto exit5; error = security_path_rename(&oldnd.path, old_dentry, &newnd.path, new_dentry);