linux 1.0 内核注解 linux/fs/super.c
时间:2009-05-02 来源:taozhijiangscu
/********************************************
*Created By: 陶治江
*Date: 2009年5月2日0:25:02
********************************************/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/locks.h> #include <asm/system.h>
#include <asm/segment.h>
/*在文件filesystems中包含了一个struct file_system_type file_systems[]
*
* struct file_system_type {
* struct super_block *(*read_super) (struct super_block *, void *, int);
* char *name;
* int requires_dev;
*};
*
*的文件系统表,在configure系统的时候填充了这个表,此时Linux系统支持的
*文件系统的类型有
*minix 1 ext 1 ext2 1 xiafs 1 msdos 1 proc 0
*nfs 0 iso9660 1 xenix 1 sysv 1 coherent 1 hpfs 1
*
*文件系统表使用NULL结尾的*/ extern struct file_system_type file_systems[];
extern struct file_operations * get_blkfops(unsigned int);
extern struct file_operations * get_chrfops(unsigned int); extern void wait_for_keypress(void);
extern void fcntl_init_locks(void); extern int root_mountflags; struct super_block super_blocks[NR_SUPER]; static int do_remount_sb(struct super_block *sb, int flags, char * data); // this is initialized in init/main.c
dev_t ROOT_DEV = 0; //根据名称返回文件系统的类型
struct file_system_type *get_fs_type(char *name)
{
int a;
if (!name) /*没有指定名称就返回第一项*/
return &file_systems[0];
for(a = 0 ; file_systems[a].read_super ; a++)
if (!strcmp(name,file_systems[a].name)) //相等
return(&file_systems[a]);
return NULL;
} void __wait_on_super(struct super_block * sb)
{
struct wait_queue wait = { current, NULL }; add_wait_queue(&sb->s_wait, &wait);
repeat: //同缓冲块的等待如出一辙
current->state = TASK_UNINTERRUPTIBLE;
if (sb->s_lock) {
schedule();
goto repeat;
}
//执行到这里就是被唤醒了的
remove_wait_queue(&sb->s_wait, &wait); //这里就删除了,所以局部变量wait不要紧的
current->state = TASK_RUNNING;
} //同步指定设备的超级块,如果脏了就调用写入操作
void sync_supers(dev_t dev)
{
struct super_block * sb; for (sb = super_blocks + 0 ; sb < super_blocks + NR_SUPER ; sb++) {
if (!sb->s_dev)
continue;
if (dev && sb->s_dev != dev)
continue;
wait_on_super(sb);
//睡眠后仍然要检查(可能睡眠中被放回了),如果没有脏就不用写入了
if (!sb->s_dev || !sb->s_dirt)
continue;
if (dev && (dev != sb->s_dev))
continue;
if (sb->s_op && sb->s_op->write_super)
sb->s_op->write_super(sb);
}
} static struct super_block * get_super(dev_t dev)
{
struct super_block * s; if (!dev)
return NULL;
s = 0+super_blocks;
while (s < NR_SUPER+super_blocks)
if (s->s_dev == dev)
{
wait_on_super(s);
if (s->s_dev == dev)
return s;
s = 0+super_blocks; //这里表示经过了睡眠后又改变了,需要从头开始检查了
} else
s++;
return NULL;
} void put_super(dev_t dev)
{
struct super_block * sb; if (dev == ROOT_DEV) { /*根文件系统,准备战斗!!*/
printk("VFS: Root device %d/%d: prepare for armageddon\n",
MAJOR(dev), MINOR(dev));
return;
}
if (!(sb = get_super(dev)))
return;
if (sb->s_covered) { //有目录挂载在这个超级块了
printk("VFS: Mounted device %d/%d - tssk, tssk\n",
MAJOR(dev), MINOR(dev));
return;
}
if (sb->s_op && sb->s_op->put_super)
sb->s_op->put_super(sb);
} //读取指定设备的超级块,如果该设备还没有超级块,就创建一个并返回
static struct super_block * read_super(dev_t dev,char *name,int flags,
void *data, int silent)
{
struct super_block * s;
struct file_system_type *type; if (!dev)
return NULL;
check_disk_change(dev);
//寻找超级块,如果找到了就返回
s = get_super(dev);
if (s)
return s;
/*否则要根据文件系统等信息进行重新加载*/
if (!(type = get_fs_type(name))) {
printk("VFS: on device %d/%d: get_fs_type(%s) failed\n",
MAJOR(dev), MINOR(dev), name);
return NULL;
}
//寻找空闲的super_block块
for (s = 0+super_blocks ;; s++) {
if (s >= NR_SUPER+super_blocks)
return NULL;
if (!s->s_dev) //没有被使用的超级块
break;
}
s->s_dev = dev;
s->s_flags = flags;
if (!type->read_super(s,data, silent)) {
s->s_dev = 0;
return NULL;
}
s->s_dev = dev;
s->s_covered = NULL; //这里还没有挂载到目录上
s->s_rd_only = 0;
s->s_dirt = 0;
return s;
} //无名块设备,不是用实际的块设备
static char unnamed_dev_in_use[256]; static dev_t get_unnamed_dev(void)
{
static int first_use = 0;
int i; if (first_use == 0) {
/*第一次使用执行的代码(静态变量),将整个数组初始化,第一个字符是没
*有使用的,这样在执行下面的代码的时候除数至少是1,系统
*就不会崩溃了*/
first_use = 1;
memset(unnamed_dev_in_use, 0, sizeof(unnamed_dev_in_use));
unnamed_dev_in_use[0] = 1; /* minor 0 (nodev) is special */
}
for (i = 0; i < sizeof unnamed_dev_in_use/sizeof unnamed_dev_in_use[0]; i++)
{
if (!unnamed_dev_in_use[i])
{
unnamed_dev_in_use[i] = 1; /*使用了*/
/*(0<<8)|i,实际返回的还是i,i的范围刚好是256
*实际的设备号是没有主设备号的*/
return (UNNAMED_MAJOR << 8) | i; //#define UNNAMED_MAJOR 0
}
}
return 0;
} static void put_unnamed_dev(dev_t dev)
{
if (!dev)
return;
if (!unnamed_dev_in_use[dev]) {
printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n",
MAJOR(dev), MINOR(dev));
return;
}
unnamed_dev_in_use[dev] = 0;
} static int do_umount(dev_t dev)
{
struct super_block * sb;
int retval;
if (dev==ROOT_DEV)
{
/*对于根文件系统需要特殊的处理:同步设备,然后
*使用只读的方法来重新挂载根文件系统*/
if (!(sb=get_super(dev)))
return -ENOENT;
if (!(sb->s_flags & MS_RDONLY)) { /*~MS_RDONLY*/
fsync_dev(dev);
retval = do_remount_sb(sb, MS_RDONLY, 0);
if (retval)
return retval;
}
return 0;
}
if (!(sb=get_super(dev)) || !(sb->s_covered)) //不能被卸载,没有被挂载
return -ENOENT;
if (!sb->s_covered->i_mount) //是否被挂载了
printk("VFS: umount(%d/%d): mounted inode has i_mount=NULL\n",
MAJOR(dev), MINOR(dev));
if (!fs_may_umount(dev, sb->s_mounted)) //这里进行尝试卸载操作,成功了就进行下面的善后操作
return -EBUSY;
//设置超级块的参数,放回相应的挂载的节点
sb->s_covered->i_mount = NULL;
iput(sb->s_covered);
sb->s_covered = NULL; //保存的是被挂载目录的节点
//同时目录节点的i_mount也保存了---
iput(sb->s_mounted);
sb->s_mounted = NULL;
//如果超级块脏了,就执行写入操作
if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super(sb);
//放回设备的超级块共其他的设备使用
put_super(dev);
return 0;
} //实际的系统调用
asmlinkage int sys_umount(char * name)
{
struct inode * inode;
dev_t dev;
int retval;
struct inode dummy_inode;
struct file_operations * fops; if (!suser())
return -EPERM;
retval = namei(name,&inode); //找到节点
if (retval) {
/*这里说明namei返回错误不一定是真的错误,而可能是
*由于符号连接的问题,使用lnamei检查*/
retval = lnamei(name,&inode);
if (retval)
return retval;
}
if (S_ISBLK(inode->i_mode)) { /*如果是块设备*/
dev = inode->i_rdev; //只有块设备才有rdev字段表示主设备和此设备号
//检查是否具有真的设备,因为这里的内核有多类文件系统了
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
} else { /*非块设备的操作*/
if (!inode || !inode->i_sb || inode != inode->i_sb->s_mounted)
{
iput(inode);
return -EINVAL;
}
dev = inode->i_sb->s_dev;
iput(inode);
memset(&dummy_inode, 0, sizeof(dummy_inode));
dummy_inode.i_rdev = dev;
inode = &dummy_inode; //节点复位操作了
//呃,看看上面的操作,实际就是保留了dev,然后所有的东西
//清零
}
if (MAJOR(dev) >= MAX_BLKDEV) {
iput(inode);
return -ENXIO;
}
if (!(retval = do_umount(dev)) && dev != ROOT_DEV)
{
fops = get_blkfops(MAJOR(dev));
if (fops && fops->release)
fops->release(inode,NULL);
/*这是对于未命名的设备进行的操作*/
if (MAJOR(dev) == UNNAMED_MAJOR) /*0*/
put_unnamed_dev(dev); //直接复位
}
if (inode != &dummy_inode)
iput(inode);
if (retval)
return retval;
fsync_dev(dev);
return 0;
} /*We cannot mount a filesystem if it has active, used, or dirty inodes.
* We also have to flush all inode-data for this device, as the new mount
* might need new info.*/
static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data)
{
struct inode * dir_i;
struct super_block * sb;
int error; error = namei(dir,&dir_i);
if (error)
return error;
//引用计数只能是1,表示在此处引用(因为在sys_mount中
//设备被打开了一次了)
//并且没有被挂载
if (dir_i->i_count != 1 || dir_i->i_mount) {
iput(dir_i);
return -EBUSY;
}
if (!S_ISDIR(dir_i->i_mode)) { //不是目录类型的文件
iput(dir_i);
return -EPERM;
}
if (!fs_may_mount(dev)) {
iput(dir_i);
return -EBUSY;
}
//注意,这里的read_super函数,如果原先的设备没有
//超级块,会自动创建一块的(这不正是我们想要的嘛)
sb = read_super(dev,type,flags,data,0);
if (!sb || sb->s_covered) { //超级块已经被安装了
iput(dir_i);
return -EBUSY;
}
//We can get sth here!
sb->s_covered = dir_i;
dir_i->i_mount = sb->s_mounted;
return 0; /* we don't iput(dir_i) - see umount */
//在do_umount()中被放回的
} //主要功能是改变已经被挂载的文件系统的挂载选项的
static int do_remount_sb(struct super_block *sb, int flags, char *data)
{
int retval;
//挂载成只读的
/* If we are remounting RDONLY, make sure there are no rw files open */
if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
if (!fs_may_remount_ro(sb->s_dev))
return -EBUSY;
if (sb->s_op && sb->s_op->remount_fs) {
retval = sb->s_op->remount_fs(sb, &flags, data);
if (retval)
return retval;
}
//记录改变后的挂载选项
//#define MS_RMT_MASK (MS_RDONLY) ~~~
sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) |
(flags & MS_RMT_MASK);
return 0;
} static int do_remount(const char *dir,int flags,char *data)
{
struct inode *dir_i;
int retval; retval = namei(dir,&dir_i);
if (retval)
return retval;
if (dir_i != dir_i->i_sb->s_mounted) { //感觉像相互备份一样
iput(dir_i);
return -EINVAL;
}
retval = do_remount_sb(dir_i->i_sb, flags, data);
iput(dir_i);
return retval;
} //就是将data数据拷贝到内核空间中,然后用where返回数据的地址
static int copy_mount_options (const void * data, unsigned long *where)
{
int i;
unsigned long page;
struct vm_area_struct * vma; *where = 0;
if (!data)
return 0; for (vma = current->mmap ; ; ) {
if (!vma ||
(unsigned long) data < vma->vm_start) {
return -EFAULT;
}
// && data>= vma->vm_start
if ((unsigned long) data < vma->vm_end)
break;
vma = vma->vm_next;
}
i = vma->vm_end - (unsigned long) data; //data是被映射到了高端虚拟内存了?
if (PAGE_SIZE <= (unsigned long) i) //最多拷贝一页??
i = PAGE_SIZE-1;
if (!(page = __get_free_page(GFP_KERNEL))) {
return -ENOMEM;
}
memcpy_fromfs((void *) page,data,i);
*where = page; //保存了页的地址了
return 0;
} /*
* Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
* be given to the mount() call (ie: read-only, no-dev, no-suid etc).
*
* data is a (void *) that can point to any structure up to
* PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
* information (or be NULL).
*
* NOTE! As old versions of mount() didn't use this setup, the flags
* has to have a special 16-bit magic number in the hight word:
* 0xC0ED. If this magic word isn't present, the flags and data info
* isn't used, as the syscall assumes we are talking to an older
* version that didn't understand them.
*/
asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void * data)
{
struct file_system_type * fstype;
struct inode * inode;
struct file_operations * fops;
dev_t dev;
int retval;
char * t;
unsigned long flags = 0;
unsigned long page = 0; if (!suser())
return -EPERM;
////含有MS_MGC_MSK魔数,而且是对已经挂载的文件系统进行重新的挂载
//魔数好像在后面的版本中被废弃了
if ((new_flags &
(MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT))
{
retval = copy_mount_options (data, &page); //page返回地址
if (retval < 0)
return retval;
retval = do_remount(dir_name,
new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
(char *) page);
free_page(page);
return retval;
}
//挂载操作
retval = copy_mount_options (type, &page);
if (retval < 0)
return retval;
fstype = get_fs_type((char *) page); //特定数据结构
free_page(page);
if (!fstype)
return -ENODEV;
t = fstype->name;
//分需名设备和无名设备的操作
if (fstype->requires_dev) {
retval = namei(dev_name,&inode);
if (retval)
return retval;
if (!S_ISBLK(inode->i_mode)) {
iput(inode);
return -ENOTBLK;
}
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
dev = inode->i_rdev;
if (MAJOR(dev) >= MAX_BLKDEV) {
iput(inode);
return -ENXIO;
}
} else {
if (!(dev = get_unnamed_dev()))
return -EMFILE;
inode = NULL;
}
fops = get_blkfops(MAJOR(dev));
if (fops && fops->open) {
retval = fops->open(inode,NULL); //打开
if (retval) {
iput(inode);
return retval;
}
}
//上面的page已经被释放了~~~
page = 0;
//不知道这里的copy_mount_options要重新操作一下呢?
//呃,上面把page清空了,所以呢,可能是对有无MS_MGC_VAL
//进行相应的操作吧
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL)
{
flags = new_flags & ~MS_MGC_MSK;
retval = copy_mount_options(data, &page);
if (retval < 0) {
iput(inode);
return retval;
}
}
//进行调用了
retval = do_mount(dev,dir_name,t,flags,(void *) page);
free_page(page);
if (retval && fops && fops->release) //错误发生
fops->release(inode,NULL);
iput(inode);
return retval;
} void mount_root(void)
{
struct file_system_type * fs_type;
struct super_block * sb;
struct inode * inode; memset(super_blocks, 0, sizeof(super_blocks));
fcntl_init_locks();
if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
wait_for_keypress();
}
for (fs_type = file_systems; fs_type->read_super; fs_type++)
{
//这些就是首先要作为根文件系统的条件
if (!fs_type->requires_dev)
continue;
//获得超级块,下面的inode的初始化(sb->s_mounted)
//应该是文件系统的底层fs_type->read_super进行的(猜的···)
sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
if (sb)
{
inode = sb->s_mounted;
inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
sb->s_covered = inode;
sb->s_flags = root_mountflags;
current->pwd = inode; //进程的当前目录
current->root = inode; //进程的根目录
printk ("VFS: Mounted root (%s filesystem)%s.\n",
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
return;
}
}
panic("VFS: Unable to mount root");
}
文档地址:http://blogimg.chinaunix.net/blog/upfile2/090502163451.pdf
*Created By: 陶治江
*Date: 2009年5月2日0:25:02
********************************************/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/stat.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/locks.h> #include <asm/system.h>
#include <asm/segment.h>
/*在文件filesystems中包含了一个struct file_system_type file_systems[]
*
* struct file_system_type {
* struct super_block *(*read_super) (struct super_block *, void *, int);
* char *name;
* int requires_dev;
*};
*
*的文件系统表,在configure系统的时候填充了这个表,此时Linux系统支持的
*文件系统的类型有
*minix 1 ext 1 ext2 1 xiafs 1 msdos 1 proc 0
*nfs 0 iso9660 1 xenix 1 sysv 1 coherent 1 hpfs 1
*
*文件系统表使用NULL结尾的*/ extern struct file_system_type file_systems[];
extern struct file_operations * get_blkfops(unsigned int);
extern struct file_operations * get_chrfops(unsigned int); extern void wait_for_keypress(void);
extern void fcntl_init_locks(void); extern int root_mountflags; struct super_block super_blocks[NR_SUPER]; static int do_remount_sb(struct super_block *sb, int flags, char * data); // this is initialized in init/main.c
dev_t ROOT_DEV = 0; //根据名称返回文件系统的类型
struct file_system_type *get_fs_type(char *name)
{
int a;
if (!name) /*没有指定名称就返回第一项*/
return &file_systems[0];
for(a = 0 ; file_systems[a].read_super ; a++)
if (!strcmp(name,file_systems[a].name)) //相等
return(&file_systems[a]);
return NULL;
} void __wait_on_super(struct super_block * sb)
{
struct wait_queue wait = { current, NULL }; add_wait_queue(&sb->s_wait, &wait);
repeat: //同缓冲块的等待如出一辙
current->state = TASK_UNINTERRUPTIBLE;
if (sb->s_lock) {
schedule();
goto repeat;
}
//执行到这里就是被唤醒了的
remove_wait_queue(&sb->s_wait, &wait); //这里就删除了,所以局部变量wait不要紧的
current->state = TASK_RUNNING;
} //同步指定设备的超级块,如果脏了就调用写入操作
void sync_supers(dev_t dev)
{
struct super_block * sb; for (sb = super_blocks + 0 ; sb < super_blocks + NR_SUPER ; sb++) {
if (!sb->s_dev)
continue;
if (dev && sb->s_dev != dev)
continue;
wait_on_super(sb);
//睡眠后仍然要检查(可能睡眠中被放回了),如果没有脏就不用写入了
if (!sb->s_dev || !sb->s_dirt)
continue;
if (dev && (dev != sb->s_dev))
continue;
if (sb->s_op && sb->s_op->write_super)
sb->s_op->write_super(sb);
}
} static struct super_block * get_super(dev_t dev)
{
struct super_block * s; if (!dev)
return NULL;
s = 0+super_blocks;
while (s < NR_SUPER+super_blocks)
if (s->s_dev == dev)
{
wait_on_super(s);
if (s->s_dev == dev)
return s;
s = 0+super_blocks; //这里表示经过了睡眠后又改变了,需要从头开始检查了
} else
s++;
return NULL;
} void put_super(dev_t dev)
{
struct super_block * sb; if (dev == ROOT_DEV) { /*根文件系统,准备战斗!!*/
printk("VFS: Root device %d/%d: prepare for armageddon\n",
MAJOR(dev), MINOR(dev));
return;
}
if (!(sb = get_super(dev)))
return;
if (sb->s_covered) { //有目录挂载在这个超级块了
printk("VFS: Mounted device %d/%d - tssk, tssk\n",
MAJOR(dev), MINOR(dev));
return;
}
if (sb->s_op && sb->s_op->put_super)
sb->s_op->put_super(sb);
} //读取指定设备的超级块,如果该设备还没有超级块,就创建一个并返回
static struct super_block * read_super(dev_t dev,char *name,int flags,
void *data, int silent)
{
struct super_block * s;
struct file_system_type *type; if (!dev)
return NULL;
check_disk_change(dev);
//寻找超级块,如果找到了就返回
s = get_super(dev);
if (s)
return s;
/*否则要根据文件系统等信息进行重新加载*/
if (!(type = get_fs_type(name))) {
printk("VFS: on device %d/%d: get_fs_type(%s) failed\n",
MAJOR(dev), MINOR(dev), name);
return NULL;
}
//寻找空闲的super_block块
for (s = 0+super_blocks ;; s++) {
if (s >= NR_SUPER+super_blocks)
return NULL;
if (!s->s_dev) //没有被使用的超级块
break;
}
s->s_dev = dev;
s->s_flags = flags;
if (!type->read_super(s,data, silent)) {
s->s_dev = 0;
return NULL;
}
s->s_dev = dev;
s->s_covered = NULL; //这里还没有挂载到目录上
s->s_rd_only = 0;
s->s_dirt = 0;
return s;
} //无名块设备,不是用实际的块设备
static char unnamed_dev_in_use[256]; static dev_t get_unnamed_dev(void)
{
static int first_use = 0;
int i; if (first_use == 0) {
/*第一次使用执行的代码(静态变量),将整个数组初始化,第一个字符是没
*有使用的,这样在执行下面的代码的时候除数至少是1,系统
*就不会崩溃了*/
first_use = 1;
memset(unnamed_dev_in_use, 0, sizeof(unnamed_dev_in_use));
unnamed_dev_in_use[0] = 1; /* minor 0 (nodev) is special */
}
for (i = 0; i < sizeof unnamed_dev_in_use/sizeof unnamed_dev_in_use[0]; i++)
{
if (!unnamed_dev_in_use[i])
{
unnamed_dev_in_use[i] = 1; /*使用了*/
/*(0<<8)|i,实际返回的还是i,i的范围刚好是256
*实际的设备号是没有主设备号的*/
return (UNNAMED_MAJOR << 8) | i; //#define UNNAMED_MAJOR 0
}
}
return 0;
} static void put_unnamed_dev(dev_t dev)
{
if (!dev)
return;
if (!unnamed_dev_in_use[dev]) {
printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n",
MAJOR(dev), MINOR(dev));
return;
}
unnamed_dev_in_use[dev] = 0;
} static int do_umount(dev_t dev)
{
struct super_block * sb;
int retval;
if (dev==ROOT_DEV)
{
/*对于根文件系统需要特殊的处理:同步设备,然后
*使用只读的方法来重新挂载根文件系统*/
if (!(sb=get_super(dev)))
return -ENOENT;
if (!(sb->s_flags & MS_RDONLY)) { /*~MS_RDONLY*/
fsync_dev(dev);
retval = do_remount_sb(sb, MS_RDONLY, 0);
if (retval)
return retval;
}
return 0;
}
if (!(sb=get_super(dev)) || !(sb->s_covered)) //不能被卸载,没有被挂载
return -ENOENT;
if (!sb->s_covered->i_mount) //是否被挂载了
printk("VFS: umount(%d/%d): mounted inode has i_mount=NULL\n",
MAJOR(dev), MINOR(dev));
if (!fs_may_umount(dev, sb->s_mounted)) //这里进行尝试卸载操作,成功了就进行下面的善后操作
return -EBUSY;
//设置超级块的参数,放回相应的挂载的节点
sb->s_covered->i_mount = NULL;
iput(sb->s_covered);
sb->s_covered = NULL; //保存的是被挂载目录的节点
//同时目录节点的i_mount也保存了---
iput(sb->s_mounted);
sb->s_mounted = NULL;
//如果超级块脏了,就执行写入操作
if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
sb->s_op->write_super(sb);
//放回设备的超级块共其他的设备使用
put_super(dev);
return 0;
} //实际的系统调用
asmlinkage int sys_umount(char * name)
{
struct inode * inode;
dev_t dev;
int retval;
struct inode dummy_inode;
struct file_operations * fops; if (!suser())
return -EPERM;
retval = namei(name,&inode); //找到节点
if (retval) {
/*这里说明namei返回错误不一定是真的错误,而可能是
*由于符号连接的问题,使用lnamei检查*/
retval = lnamei(name,&inode);
if (retval)
return retval;
}
if (S_ISBLK(inode->i_mode)) { /*如果是块设备*/
dev = inode->i_rdev; //只有块设备才有rdev字段表示主设备和此设备号
//检查是否具有真的设备,因为这里的内核有多类文件系统了
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
} else { /*非块设备的操作*/
if (!inode || !inode->i_sb || inode != inode->i_sb->s_mounted)
{
iput(inode);
return -EINVAL;
}
dev = inode->i_sb->s_dev;
iput(inode);
memset(&dummy_inode, 0, sizeof(dummy_inode));
dummy_inode.i_rdev = dev;
inode = &dummy_inode; //节点复位操作了
//呃,看看上面的操作,实际就是保留了dev,然后所有的东西
//清零
}
if (MAJOR(dev) >= MAX_BLKDEV) {
iput(inode);
return -ENXIO;
}
if (!(retval = do_umount(dev)) && dev != ROOT_DEV)
{
fops = get_blkfops(MAJOR(dev));
if (fops && fops->release)
fops->release(inode,NULL);
/*这是对于未命名的设备进行的操作*/
if (MAJOR(dev) == UNNAMED_MAJOR) /*0*/
put_unnamed_dev(dev); //直接复位
}
if (inode != &dummy_inode)
iput(inode);
if (retval)
return retval;
fsync_dev(dev);
return 0;
} /*We cannot mount a filesystem if it has active, used, or dirty inodes.
* We also have to flush all inode-data for this device, as the new mount
* might need new info.*/
static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data)
{
struct inode * dir_i;
struct super_block * sb;
int error; error = namei(dir,&dir_i);
if (error)
return error;
//引用计数只能是1,表示在此处引用(因为在sys_mount中
//设备被打开了一次了)
//并且没有被挂载
if (dir_i->i_count != 1 || dir_i->i_mount) {
iput(dir_i);
return -EBUSY;
}
if (!S_ISDIR(dir_i->i_mode)) { //不是目录类型的文件
iput(dir_i);
return -EPERM;
}
if (!fs_may_mount(dev)) {
iput(dir_i);
return -EBUSY;
}
//注意,这里的read_super函数,如果原先的设备没有
//超级块,会自动创建一块的(这不正是我们想要的嘛)
sb = read_super(dev,type,flags,data,0);
if (!sb || sb->s_covered) { //超级块已经被安装了
iput(dir_i);
return -EBUSY;
}
//We can get sth here!
sb->s_covered = dir_i;
dir_i->i_mount = sb->s_mounted;
return 0; /* we don't iput(dir_i) - see umount */
//在do_umount()中被放回的
} //主要功能是改变已经被挂载的文件系统的挂载选项的
static int do_remount_sb(struct super_block *sb, int flags, char *data)
{
int retval;
//挂载成只读的
/* If we are remounting RDONLY, make sure there are no rw files open */
if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
if (!fs_may_remount_ro(sb->s_dev))
return -EBUSY;
if (sb->s_op && sb->s_op->remount_fs) {
retval = sb->s_op->remount_fs(sb, &flags, data);
if (retval)
return retval;
}
//记录改变后的挂载选项
//#define MS_RMT_MASK (MS_RDONLY) ~~~
sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) |
(flags & MS_RMT_MASK);
return 0;
} static int do_remount(const char *dir,int flags,char *data)
{
struct inode *dir_i;
int retval; retval = namei(dir,&dir_i);
if (retval)
return retval;
if (dir_i != dir_i->i_sb->s_mounted) { //感觉像相互备份一样
iput(dir_i);
return -EINVAL;
}
retval = do_remount_sb(dir_i->i_sb, flags, data);
iput(dir_i);
return retval;
} //就是将data数据拷贝到内核空间中,然后用where返回数据的地址
static int copy_mount_options (const void * data, unsigned long *where)
{
int i;
unsigned long page;
struct vm_area_struct * vma; *where = 0;
if (!data)
return 0; for (vma = current->mmap ; ; ) {
if (!vma ||
(unsigned long) data < vma->vm_start) {
return -EFAULT;
}
// && data>= vma->vm_start
if ((unsigned long) data < vma->vm_end)
break;
vma = vma->vm_next;
}
i = vma->vm_end - (unsigned long) data; //data是被映射到了高端虚拟内存了?
if (PAGE_SIZE <= (unsigned long) i) //最多拷贝一页??
i = PAGE_SIZE-1;
if (!(page = __get_free_page(GFP_KERNEL))) {
return -ENOMEM;
}
memcpy_fromfs((void *) page,data,i);
*where = page; //保存了页的地址了
return 0;
} /*
* Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
* be given to the mount() call (ie: read-only, no-dev, no-suid etc).
*
* data is a (void *) that can point to any structure up to
* PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
* information (or be NULL).
*
* NOTE! As old versions of mount() didn't use this setup, the flags
* has to have a special 16-bit magic number in the hight word:
* 0xC0ED. If this magic word isn't present, the flags and data info
* isn't used, as the syscall assumes we are talking to an older
* version that didn't understand them.
*/
asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
unsigned long new_flags, void * data)
{
struct file_system_type * fstype;
struct inode * inode;
struct file_operations * fops;
dev_t dev;
int retval;
char * t;
unsigned long flags = 0;
unsigned long page = 0; if (!suser())
return -EPERM;
////含有MS_MGC_MSK魔数,而且是对已经挂载的文件系统进行重新的挂载
//魔数好像在后面的版本中被废弃了
if ((new_flags &
(MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT))
{
retval = copy_mount_options (data, &page); //page返回地址
if (retval < 0)
return retval;
retval = do_remount(dir_name,
new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
(char *) page);
free_page(page);
return retval;
}
//挂载操作
retval = copy_mount_options (type, &page);
if (retval < 0)
return retval;
fstype = get_fs_type((char *) page); //特定数据结构
free_page(page);
if (!fstype)
return -ENODEV;
t = fstype->name;
//分需名设备和无名设备的操作
if (fstype->requires_dev) {
retval = namei(dev_name,&inode);
if (retval)
return retval;
if (!S_ISBLK(inode->i_mode)) {
iput(inode);
return -ENOTBLK;
}
if (IS_NODEV(inode)) {
iput(inode);
return -EACCES;
}
dev = inode->i_rdev;
if (MAJOR(dev) >= MAX_BLKDEV) {
iput(inode);
return -ENXIO;
}
} else {
if (!(dev = get_unnamed_dev()))
return -EMFILE;
inode = NULL;
}
fops = get_blkfops(MAJOR(dev));
if (fops && fops->open) {
retval = fops->open(inode,NULL); //打开
if (retval) {
iput(inode);
return retval;
}
}
//上面的page已经被释放了~~~
page = 0;
//不知道这里的copy_mount_options要重新操作一下呢?
//呃,上面把page清空了,所以呢,可能是对有无MS_MGC_VAL
//进行相应的操作吧
if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL)
{
flags = new_flags & ~MS_MGC_MSK;
retval = copy_mount_options(data, &page);
if (retval < 0) {
iput(inode);
return retval;
}
}
//进行调用了
retval = do_mount(dev,dir_name,t,flags,(void *) page);
free_page(page);
if (retval && fops && fops->release) //错误发生
fops->release(inode,NULL);
iput(inode);
return retval;
} void mount_root(void)
{
struct file_system_type * fs_type;
struct super_block * sb;
struct inode * inode; memset(super_blocks, 0, sizeof(super_blocks));
fcntl_init_locks();
if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
wait_for_keypress();
}
for (fs_type = file_systems; fs_type->read_super; fs_type++)
{
//这些就是首先要作为根文件系统的条件
if (!fs_type->requires_dev)
continue;
//获得超级块,下面的inode的初始化(sb->s_mounted)
//应该是文件系统的底层fs_type->read_super进行的(猜的···)
sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
if (sb)
{
inode = sb->s_mounted;
inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */
sb->s_covered = inode;
sb->s_flags = root_mountflags;
current->pwd = inode; //进程的当前目录
current->root = inode; //进程的根目录
printk ("VFS: Mounted root (%s filesystem)%s.\n",
fs_type->name,
(sb->s_flags & MS_RDONLY) ? " readonly" : "");
return;
}
}
panic("VFS: Unable to mount root");
}
文档地址:http://blogimg.chinaunix.net/blog/upfile2/090502163451.pdf
相关阅读 更多 +
排行榜 更多 +