aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/mount.h9
-rw-r--r--fs/namei.c6
-rw-r--r--fs/namespace.c35
3 files changed, 49 insertions, 1 deletions
diff --git a/fs/mount.h b/fs/mount.h
index 8f2a14ae38a2..8c6a2a651254 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -115,3 +115,12 @@ struct proc_mounts {
115#define proc_mounts(p) (container_of((p), struct proc_mounts, m)) 115#define proc_mounts(p) (container_of((p), struct proc_mounts, m))
116 116
117extern const struct seq_operations mounts_op; 117extern const struct seq_operations mounts_op;
118
119extern bool __is_local_mountpoint(struct dentry *dentry);
120static inline bool is_local_mountpoint(struct dentry *dentry)
121{
122 if (!d_mountpoint(dentry))
123 return false;
124
125 return __is_local_mountpoint(dentry);
126}
diff --git a/fs/namei.c b/fs/namei.c
index a7b05bf82d31..a3a14b033b0d 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3565,6 +3565,8 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
3565 mutex_lock(&dentry->d_inode->i_mutex); 3565 mutex_lock(&dentry->d_inode->i_mutex);
3566 3566
3567 error = -EBUSY; 3567 error = -EBUSY;
3568 if (is_local_mountpoint(dentry))
3569 goto out;
3568 if (d_mountpoint(dentry)) 3570 if (d_mountpoint(dentry))
3569 goto out; 3571 goto out;
3570 3572
@@ -3681,7 +3683,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate
3681 return -EPERM; 3683 return -EPERM;
3682 3684
3683 mutex_lock(&target->i_mutex); 3685 mutex_lock(&target->i_mutex);
3684 if (d_mountpoint(dentry)) 3686 if (is_local_mountpoint(dentry) || d_mountpoint(dentry))
3685 error = -EBUSY; 3687 error = -EBUSY;
3686 else { 3688 else {
3687 error = security_inode_unlink(dir, dentry); 3689 error = security_inode_unlink(dir, dentry);
@@ -4126,6 +4128,8 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
4126 mutex_lock(&target->i_mutex); 4128 mutex_lock(&target->i_mutex);
4127 4129
4128 error = -EBUSY; 4130 error = -EBUSY;
4131 if (is_local_mountpoint(old_dentry) || is_local_mountpoint(new_dentry))
4132 goto out;
4129 if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry)) 4133 if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry))
4130 goto out; 4134 goto out;
4131 4135
diff --git a/fs/namespace.c b/fs/namespace.c
index 044134315f93..77ffdb82f63f 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -667,6 +667,41 @@ struct vfsmount *lookup_mnt(struct path *path)
667 return m; 667 return m;
668} 668}
669 669
670/*
671 * __is_local_mountpoint - Test to see if dentry is a mountpoint in the
672 * current mount namespace.
673 *
674 * The common case is dentries are not mountpoints at all and that
675 * test is handled inline. For the slow case when we are actually
676 * dealing with a mountpoint of some kind, walk through all of the
677 * mounts in the current mount namespace and test to see if the dentry
678 * is a mountpoint.
679 *
680 * The mount_hashtable is not usable in the context because we
681 * need to identify all mounts that may be in the current mount
682 * namespace not just a mount that happens to have some specified
683 * parent mount.
684 */
685bool __is_local_mountpoint(struct dentry *dentry)
686{
687 struct mnt_namespace *ns = current->nsproxy->mnt_ns;
688 struct mount *mnt;
689 bool is_covered = false;
690
691 if (!d_mountpoint(dentry))
692 goto out;
693
694 down_read(&namespace_sem);
695 list_for_each_entry(mnt, &ns->list, mnt_list) {
696 is_covered = (mnt->mnt_mountpoint == dentry);
697 if (is_covered)
698 break;
699 }
700 up_read(&namespace_sem);
701out:
702 return is_covered;
703}
704
670static struct mountpoint *new_mountpoint(struct dentry *dentry) 705static struct mountpoint *new_mountpoint(struct dentry *dentry)
671{ 706{
672 struct hlist_head *chain = mp_hash(dentry); 707 struct hlist_head *chain = mp_hash(dentry);