]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/namei.c
Merge remote-tracking branch 'userns/for-next'
[karo-tx-linux.git] / fs / namei.c
index caa28051e197e898e3c2bc52afce37bcbb284853..f892ef9b3ead08b6ffea75833349d58d889e42c6 100644 (file)
@@ -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);