文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>linux 1.0 内核注解 linux/fs/super.c

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
相关阅读 更多 +
排行榜 更多 +
捕鱼大咖官方正版下载

捕鱼大咖官方正版下载

角色扮演 下载
方舟生存进化2.0手机版下载安装

方舟生存进化2.0手机版下载安装

角色扮演 下载
图书馆挠痒大作战游戏下载

图书馆挠痒大作战游戏下载

休闲益智 下载