Chinaunix首页 | 论坛 | 博客
  • 博客访问: 280804
  • 博文数量: 68
  • 博客积分: 3061
  • 博客等级: 中校
  • 技术积分: 652
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-27 11:39
文章分类

全部博文(68)

文章存档

2018年(1)

2017年(2)

2016年(1)

2014年(2)

2012年(6)

2011年(14)

2010年(38)

2008年(4)

我的朋友

分类: LINUX

2010-07-29 10:07:56

1、重要的数据结构
 要了解/的建立就需要了解FileSystem的一些基本的数据结构
1.1 全局static struct file_system_type *file_systems。
struct file_system_type {
const char *name;//文件系统名
int fs_flags;//标志位
        /* 获得超级块的方法*/
int (*get_sb) (struct file_system_type *, int,
      const char *, void *, struct vfsmount *);
        /* 删除超级块的方法 */
void (*kill_sb) (struct super_block *);
struct module *owner;
        /* 下一个文件系统类型 */
struct file_system_type * next;
struct list_head fs_supers;
struct lock_class_key s_lock_key;
struct lock_class_key s_umount_key;
};

作用:链接各种文件系统链表:ext2,ext3,rootfs,......

1.2 全局链表头LIST_HEAD(super_blocks)
LIST_HEAD:定义在list.h中
struct list_head {
struct list_head *next, *prev;
};
#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
最终形式:struct list_head list = {&list,&list};
作用:链接所有文件系统的超级块

1.3 全局链表头
  LIST_HEAD(inode_in_use);
  LIST_HEAD(inode_unused);

1.4 struct vfsmount
{
struct list_head mnt_hash;
struct vfsmount *mnt_parent; /* fs we are mounted on */
struct dentry *mnt_mountpoint; /* dentry of mountpoint */
struct dentry *mnt_root; /* root of the mounted tree */
struct super_block *mnt_sb; /* pointer to superblock */
struct list_head mnt_mounts; /* list of children, anchored here */
struct list_head mnt_child; /* and going through their mnt_child */
atomic_t mnt_count;
int mnt_flags;
int mnt_expiry_mark; /* true if marked for expiry */
char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
struct list_head mnt_list;
struct list_head mnt_fslink; /* link in fs-specific expiry list */
struct namespace *mnt_namespace; /* containing namespace */
};

1.5 struct inode {
struct hlist_node i_hash;
struct list_head i_list;
struct list_head i_sb_list;
struct list_head i_dentry;
unsigned long i_ino;
atomic_t i_count;
unsigned int i_nlink;
uid_t i_uid;
gid_t i_gid;
dev_t i_rdev;
unsigned long i_version;
loff_t i_size;
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
struct timespec i_atime;
struct timespec i_mtime;
struct timespec i_ctime;
unsigned int i_blkbits;
blkcnt_t i_blocks;
unsigned short          i_bytes;
umode_t i_mode;
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
struct mutex i_mutex;
struct rw_semaphore i_alloc_sem;
const struct inode_operations *i_op;
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct super_block *i_sb;
struct file_lock *i_flock;
struct address_space *i_mapping;
struct address_space i_data;
#ifdef CONFIG_QUOTA
struct dquot *i_dquot[MAXQUOTAS];
#endif
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
struct cdev *i_cdev;
};
int i_cindex;

__u32 i_generation;

#ifdef CONFIG_DNOTIFY
unsigned long i_dnotify_mask; /* Directory notify events */
struct dnotify_struct *i_dnotify; /* for directory notifications */
#endif

#ifdef CONFIG_INOTIFY
struct list_head inotify_watches; /* watches on this inode */
struct mutex inotify_mutex; /* protects the watches list */
#endif

unsigned long i_state;
unsigned long dirtied_when; /* jiffies of first dirtying */

unsigned int i_flags;

atomic_t i_writecount;
#ifdef CONFIG_SECURITY
void *i_security;
#endif
void *i_private; /* fs or device private pointer */
};

1.6 struct dentry {
atomic_t d_count;
unsigned int d_flags; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
/*
* The next three fields are touched by __d_lookup.  Place them here
* so they all fit in a cache line.
*/
struct hlist_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */
struct qstr d_name;

struct list_head d_lru; /* LRU list */
/*
* d_child and d_rcu can share memory
*/
union {
struct list_head d_child; /* child of parent list */
struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs; /* our children */
struct list_head d_alias; /* inode alias list */
unsigned long d_time; /* used by d_revalidate */
struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
void *d_fsdata; /* fs-specific data */
#ifdef CONFIG_PROFILING
struct dcookie_struct *d_cookie; /* cookie, if any */
#endif
int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};


2、建立过程
2.1 start_kernel->vfs_caches_init(num_physpages)
                               ->mnt_init->init_rootfs()->init_mount_tree()
  从init_rootfs(),开始分析。

2.2 init_rootfs()
  它只是调用了register_filesystem(struct file_system_type * fs),将一个静态的
static struct file_system_type rootfs_fs_type = {
.name = "rootfs",
.get_sb = rootfs_get_sb,
.kill_sb = kill_litter_super,
};注册file_systems中。可以看出要让kernel新增一个filesystem应先做这步。

2.3 init_mount_tree()
  a) 首先调用do_kern_mount("rootfs", 0, "rootfs", NULL)
             【原型:(const char *fstype, int flags, const char *name, void *data)】
     获得一个struct vfsmount *mnt,将rootfs文件系统挂载,  这个函数做的事情比较多,后面会详细说明

  b) 申请并初始化:struct mnt_namespace *ns
     然后将mnt 和 ns 捆绑。ns在filesystem中的作用未理解。两者关系如下图:
        
c) 当前init_task的nsproxy->mnt_ns置为当前的ns.(struct task_struct中的nsproxy不是很理解)
   init_task.nsproxy->mnt_ns = ns

d) 将当前进程的根目录和当前目录切换到"/"
    set_fs_pwd(current->fs, ns->root, ns->root->mnt_root);
set_fs_root(current->fs, ns->root, ns->root->mnt_root); 

3、do_kern_mount(const char *fstype, int flags, const char *name, void *data)
这里主要是获得当前文件系统的的类型,并通过vfs_kern_mount获得struct vfsmount mnt,do_kern_mount的也就结束了。
 下面具体分析vfs_kern_mount

3.1 申请mnt所需空间并初始化部分成员。

3.2 获得超级块 rootfs_get_sb(type, 0, "rootfs", NULL, mnt),它最终调用了->get_sb_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super,mnt)
get_sb_nodev又调用了:
     sget(fs_type, NULL, set_anon_super, NULL);
       ramfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
       simple_set_mnt(mnt, s);
       这几个函数比较重要,下面一一说明。
       
   a) struct super_block *sget(struct file_system_type *type,
int (*test)(struct super_block *,void *),
int (*set)(struct super_block *,void *),
void *data)
     申请struct super_block 空间,通过set(super_block, data),设置super_block中的s_dev。将super_block和struct file_system rootfs绑定,两者关系如下图:

   b) ramfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0)
      填充了rootfs的super_block,指定了super_block一系列的操作函数super_operations ramfs_ops,并通过ramfs_get_inode、d_alloc_root两个函数申请了root_inode和root_dentry,并做初始化。
  • ramfs_get_inode
      调用new_inode->alloc_inode申请inode所需空间,并初始化部分节点,执行inodes_stat.nr_inodes++,将inode链接至全局变量inde_in_use,和super_block。
      
    static const struct address_space_operations empty_aops
      static struct inode_operations empty_iops;
      static const struct file_operations empty_fops;

      struct address_space * const mapping = &inode->i_data;
      inode->i_op = &empty_iops; /*inode 的一些操作*/
      inode->i_fop = &empty_fops; /* 文件的一些列操作 */
      mapping->a_ops = &empty_aops;/* inode地址空间的操作 */
  • d_alloc_root 
    static const struct qstr name = { .name = "/", .len = 1 }
    调用d_alloc(NULL, &name)申请并分配并初始化root_dentry。并执行dentry_stat.nr_dentry++;
    执行完上述两个函数后,将执行d_instantiate()将inode和dentry对应起来,并针对inode和dentry的做了cache操作,这个不做研究。 

 c) simple_set_mnt
    这个函数相对简单,直接上源码。
int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
{
mnt->mnt_sb = sb;
mnt->mnt_root = dget(sb->s_root);
return 0;
}

3.3  将mnt->mnt_mountpoint挂载点设为super_block设置的root_dentry,将mnt->mnt_parent 指向自己。
     do_kern_mount也就分析完了。


4、小结
   通过上面的函数 我们总共有了
   file_system_type rootfs
   struct super_block s
   file_struct vfsmount *mnt
   struct mnt_namespace *ns
   struct inode
   struct dentry 他们见的关系图如下:


  
   

阅读(1067) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~