Linux内核源码分析-安装普通文件系统-mount系统调用
本文主要参考《深入理解Linux内核》,结合2.6.11.1版的内核代码,分析内核文件子系统中的安装普通文件系统函数。
注意:
1、不描述内核同步、错误处理、参数合法性验证相关的内容
2、源码摘自Linux内核2.6.11.1版
3、阅读本文请结合《深入理解Linux内核》第三版相关章节
4、本文会不定时更新
1、sys_mount
函数源码:
asmlinkage long sys_mount(char __user *dev_name, char __user * dir_name,
char __user * type, unsigned long flags,
void __user * data)
{
intretval;
unsignedlong data_page;
unsignedlong type_page;
unsignedlong dev_page;
char*dir_page;
//从用户空间复制文件系统类型字符串到type_page指向的内存地址
retval= copy_mount_options (type, &type_page);
if(retval < 0)
returnretval;
//从用户空间获取路径名
dir_page= getname(dir_name);
retval= PTR_ERR(dir_page);
if(IS_ERR(dir_page))
gotoout1;
//从用户空间复制块设备文件名到内核空间
retval= copy_mount_options (dev_name, &dev_page);
if(retval < 0)
gotoout2;
//复制与文件系统相关的数据结构的地址
retval= copy_mount_options (data, &data_page);
if(retval < 0)
gotoout3;
lock_kernel();
//分析见下文
retval= do_mount((char*)dev_page, dir_page, (char*)type_page,
flags, (void*)data_page);
unlock_kernel();
free_page(data_page);
out3:
free_page(dev_page);
out2:
putname(dir_page);
out1:
free_page(type_page);
returnretval;
}
函数处理流程:
从用户空间复制数据到内核空间(准备参数)、获取大内核锁、调用do_mount函数
2、copy_mount_options
函数源码:
int copy_mount_options(const void__user *data, unsigned long *where)
{
inti;
unsignedlong page;
unsignedlong size;
*where= 0;
if(!data)
return0;
if(!(page = __get_free_page(GFP_KERNEL)))
return-ENOMEM;
/*We only care that *some* data at the address the user
* gave us is valid. Just in case, we'll zero
* the remainder of the page.
*/
/*copy_from_user cannot cross TASK_SIZE ! */
size= TASK_SIZE - (unsigned long)data;
if(size > PAGE_SIZE)
size= PAGE_SIZE;
i= size - exact_copy_from_user((void *)page, data, size);
if(!i) {
free_page(page);
return-EFAULT;
}
if(i != PAGE_SIZE)
memset((char*)page + i, 0, PAGE_SIZE - i);
*where= page;
return0;
}
函数处理流程:
1、调用函数__get_free_page分配一个空闲页框并返回页框的线性地址
2、调用函数exact_copy_from_user把用户空间的数据从data