-
/*
-
* add a mount into a namespace's mount tree
-
* - provide the option of adding the new mount to an expiration list
-
*/
-
int do_add_mount(struct vfsmount *newmnt, struct path *path,
-
int mnt_flags, struct list_head *fslist)
-
{
-
int err;
-
-
mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
-
-
down_write(&namespace_sem);
/* 防止在等待信号量的过程中有人捷足先登,在mount_point上又mount了其他设备
如果有其他设备抢先mount到了这个mountponit,那么对不起,我只能用它的root dentry作为新的mountponit了,
所以这里调用follow_down,直到找到最新抢先mount的设备的root dentry */
-
/* Something was mounted here while we slept */
-
while (d_mountpoint(path->dentry) &&
-
follow_down(path))
-
;
-
err = -EINVAL;
-
if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
-
goto unlock;
/* 防止同一个设备mount到同一个mountpoint */
-
/* Refuse the same filesystem on the same mount point */
-
err = -EBUSY;
-
if (path->mnt->mnt_sb == newmnt->mnt_sb &&
-
path->mnt->mnt_root == path->dentry)
-
goto unlock;
/* 设备的根节点不能是符号链接 */
-
err = -EINVAL;
-
if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
-
goto unlock;
-
/* graft_tree实现newmnt(也即是childmount)与parent mount建立联系 */
-
newmnt->mnt_flags = mnt_flags;
-
if ((err = graft_tree(newmnt, path)))
-
goto unlock;
/* do_new_mount传递过来的fslist为NULL */
-
if (fslist) /* add to the specified expiration list */
-
list_add_tail(&newmnt->mnt_expire, fslist);
-
-
up_write(&namespace_sem);
-
return 0;
-
-
unlock:
-
up_write(&namespace_sem);
-
mntput(newmnt);
-
return err;
-
}