For the call of the mount System Involved in the installation of the preceding root directory file system, we consider that a file system will be installed on an installed file system, that is, call the mount System Call implementation. The mount System Call is used to install a common file system. Its service routine is sys_mount ().
/* Sys_mount system call */
/* Dev_name is the path name of the device to be installed;
Dir_name is the installed path name;
Type is a string that represents the file system type;
*/
SYSCALL_DEFINE5 (mount, char _ user *, dev_name, char _ user *, dir_name,
Char _ user *, type, unsigned long, flags, void _ user *, data)
{
Int ret;
Char * kernel_type;
Char * kernel_dir;
Char * kernel_dev;
Unsigned long data_page;
/* Copy from user space to system space */
Ret = copy_mount_string (type, & kernel_type );
If (ret <0)
Goto out_type;
Kernel_dir = getname (dir_name );
If (IS_ERR (kernel_dir )){
Ret = PTR_ERR (kernel_dir );
Goto out_dir;
}
Ret = copy_mount_string (dev_name, & kernel_dev );
If (ret <0)
Goto out_dev;
/* Copy the user space to the system space and the entire page */
Ret = copy_mount_options (data, & data_page );
If (ret <0)
Goto out_data;
/* Operator */
Ret = do_mount (kernel_dev, kernel_dir, kernel_type, flags,
(Void *) data_page );
Free_page (data_page );
Out_data:
Kfree (kernel_dev );
Out_dev:
Putname (kernel_dir );
Out_dir:
Kfree (kernel_type );
Out_type:
Return ret;
}
The following is the subject implementation
Long do_mount (char * dev_name, char * dir_name, char * type_page,
Unsigned long flags, void * data_page)
{
Struct path;
Int retval = 0;
Int mnt_flags = 0;
/* Discard magic */
If (flags & MS_MGC_MSK) = MS_MGC_VAL)
Flags & = ~ MS_MGC_MSK;
/* Basic sanity checks */
If (! Dir_name |! * Dir_name |! Memchr (dir_name, 0, PAGE_SIZE ))
Return-EINVAL;
If (data_page)
(Char *) data_page) [PAGE_SIZE-1] = 0;
/* Default to relatime unless overriden */
If (! (Flags & MS_NOATIME ))
Mnt_flags | = MNT_RELATIME;
/* Separate the per-mountpoint flags */
If (flags & MS_NOSUID)
Mnt_flags | = MNT_NOSUID;
If (flags & MS_NODEV)
Mnt_flags | = MNT_NODEV;
If (flags & MS_NOEXEC)
Mnt_flags | = MNT_NOEXEC;
If (flags & MS_NOATIME)
Mnt_flags | = MNT_NOATIME;
If (flags & MS_NODIRATIME)
Mnt_flags | = MNT_NODIRATIME;
If (flags & MS_STRICTATIME)
Mnt_flags & = ~ (MNT_RELATIME | MNT_NOATIME );
If (flags & MS_RDONLY)
Mnt_flags | = MNT_READONLY;
Flags & = ~ (MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE |
MS_NOATIME | MS_NODIRATIME | MS_RELATIME | MS_KERNMOUNT |
MS_STRICTATIME );
/*... And get the mountpoint */
/* Obtain the installation path Structure */
Retval = kern_path (dir_name, LOOKUP_FOLLOW, & path );
If (retval)
Return retval;
Retval = security_sb_mount (dev_name, & path,
Type_page, flags, data_page );
If (retval)
Goto dput_out;
If (flags & MS_REMOUNT)
/* Modify the existing file system parameters, that is, change the super block object s_flags.
Field installation flag */
Retval = do_remount (& path, flags &~ MS_REMOUNT, mnt_flags,
Data_page );
Else if (flags & MS_BIND)
/* Files or directories must be visible at another installation point in the system directory tree */
Retval = do_loopback (& path, dev_name, flags & MS_REC );
Else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE ))
/* Is responsible for handling shared, slave, and unbindable mounts by changing
The mount flags or building up the required data structure connections
Between the vfsmount
Instances involved .*/
Retval = do_change_type (& path, flags );
Else if (flags & MS_MOVE)
/* Change the Installation Point of the installed file */
/* Used to move a mounted filesystem */
Retval = do_move_mount (& path, dev_name );
Else
/* Handles normal mount operations. This is the default situation, so no special
Flags
Are required */
/* When the user requires to install a special file system or store it in a disk partition
*/
Retval = do_new_mount (& path, type_page, flags, mnt_flags,
Dev_name, data_page );
Dput_out:
Path_put (& path );
Return retval;
}
/*
* Create a new mount for userspace and request it to be added into
* Namespace's tree
*/
Static int do_new_mount (struct path * path, char * type, int flags,
Int mnt_flags, char * name, void * data)
{
Struct vfsmount * mnt;
If (! Type)
Return-EINVAL;
/* We need capabilities ...*/
If (! Capable (CAP_SYS_ADMIN ))
Return-EPERM;
Lock_kernel ();
/* Handle the actual installation operation and return a New Installation File System
Descriptor address. Use get_fs_type to scan the Linked List of Registered file systems.
Find the matching file_system_type instance. Then allocate or obtain the sb Structure
And associated with mnt, initialize mnt and return */
*/
Mnt = do_kern_mount (type, flags, name, data );
Unlock_kernel ();
If (IS_ERR (mnt ))
Return PTR_ERR (mnt );
/* Handle the necessary lock operations to ensure that a file system will not be loaded
Integrate the file system into the system at the same location */
Return do_add_mount (mnt, path, mnt_flags, NULL );
}
The do_kern_mount function has been introduced in the previous initialization. The following describes how to use the do_add_mount function to integrate the file system into the system.
/*
* 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;
Down_write (& namespace_sem );
/* Something was mounted here while we slept */
While (d_mountpoint (path-> dentry )&&
Follow_down (path ))
;
Err =-EINVAL;
/* Verify whether the file system recently installed on the reinstallation point points
Current namespace */
If (! (Mnt_flags & MNT_SHRINKABLE )&&! Check_mnt (path-> mnt ))
Goto unlock;
/* Refuse the same filesystem on the same mount point */
Err =-EBUSY;
/* If the file system to be installed has been installed in a parameter called by the System
The specified Installation Point */
If (path-> mnt-> mnt_sb = newmnt-> mnt_sb &&
Path-> mnt-> mnt_root = path-> dentry)
Goto unlock;
Err =-EINVAL;
/* This installation point is a symbolic link */
If (S_ISLNK (newmnt-> mnt_root-> d_inode-> I _mode ))
Goto unlock;
Newmnt-> mnt_flags = mnt_flags;
/* Insert the newly installed file system object to the namespace linked list,
Hash list and sub-linked list of the parent File System */
If (err = graft_tree (newmnt, path )))
Goto unlock;
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;
}
The newly installed file system object is linked to the system tree.
Static int graft_tree (struct vfsmount * mnt, struct path * path)
{
Int err;
If (mnt-> mnt_sb-> s_flags & MS_NOUSER)
Return-EINVAL;
If (S_ISDIR (path-> dentry-> d_inode-> I _mode )! =
S_ISDIR (mnt-> mnt_root-> d_inode-> I _mode ))
Return-ENOTDIR;
Err =-ENOENT;
Mutex_lock (& path-> dentry-> d_inode-> I _mutex );
If (IS_DEADDIR (path-> dentry-> d_inode ))
Goto out_unlock;
Err = security_sb_check_sb (mnt, path );
If (err)
Goto out_unlock;
Err =-ENOENT;
If (! D_unlinked (path-> dentry)/* Add to tree */
Err = attach_recursive_mnt (mnt, path, NULL );
Out_unlock:
Mutex_unlock (& path-> dentry-> d_inode-> I _mutex );
If (! Err)
Security_sb_post_addmount (mnt, path );
Return err;
}
/* Add the file system to the namespace of the parent File System */
Static int attach_recursive_mnt (struct vfsmount * source_mnt,
Struct path * path, struct path * parent_path)
{
LIST_HEAD (tree_list );
Struct vfsmount * dest_mnt = path-> mnt;
Struct dentry * dest_dentry = path-> dentry;
Struct vfsmount * child, * p;
Int err;
If (IS_MNT_SHARED (dest_mnt )){
Err = invent_group_ids (source_mnt, true );
If (err)
Goto out;
}
Err = propagate_mnt (dest_mnt, dest_dentry, source_mnt, & tree_list );
If (err)
Goto out_cleanup_ids;
If (IS_MNT_SHARED (dest_mnt )){
For (p = source_mnt; p = next_mnt (p, source_mnt ))
Set_mnt_shared (p );
}
Spin_lock (& vfsmount_lock );
If (parent_path ){
Detach_mnt (source_mnt, parent_path );
Attach_mnt (source_mnt, path );
Touch_mnt_namespace (parent_path-> mnt-> mnt_ns );
} Else {
/* Ensure that the mnt_parent member of the new vfsmount instance points to the parent File System
And mnt_mountpoint points to the parent file.
Dentry instance in the system */
Mnt_set_mountpoint (dest_mnt, dest_dentry, source_mnt );
Commit_tree (source_mnt );
}
List_for_each_entry_safe (child, p, & tree_list, mnt_hash ){
List_del_init (& child-> mnt_hash );
/* Add the new mnt to the global hash and the parent File System mnt instance.
Sub-file system linked list */
Commit_tree (child );
}
Spin_unlock (& vfsmount_lock );
Return 0;
Out_cleanup_ids:
If (IS_MNT_SHARED (dest_mnt ))
Cleanup_group_ids (source_mnt, NULL );
Out:
Return err;
}
Bullbat Column