格式化源码: mkexofs.c mkexofs_main.c mkexofs.h (~/open-osd/usr)
格式化步骤:
1.
调用osd_open()(~/open-osd/lib/osddev.c)打开对应的osd设备,并将打开的osd设备信息保存于类型为struct osd_dev的数组中。
2.
调用mkexofs.format()(~/open-osd/usr)根据一些选项对打开的osd设备进行格式化。
3.
调用osd_closd()(~/open-osd/lib/osddev.c)关闭之前打开的osd设备。
格式化过程中对每个OSD设备执行如下操作:
1.
对OSD设备进行格式化,请求设备服务器格式化整个OSD,即删除所有的用户对象,删除处0号分区以外的所有分区对象,而后按照约定重新设置根对象和第0号分区对象的属性。格式化的目的是创建一个新的OSD逻辑单元。(由函数_format()实现)
2.
在每个OSD设备上创建分区对象(由函数mkfs_one()调用create_partition()实现),分区对象的ID号为先前命令中传入的PID。(这说明一个分区上就放着一个文件系统,但是这个分区跨不同的对象设备?)
3.
创建超级块对象,对象号为{ pid,
EXOFS_SUPER_ID},其中EXOFS_SUPER_ID为0x10000。(由函数mkfs_one()调用create ()实现)
4.
创建根目录对象,对象号为{ pid,
EXOFS_ROOT_ID},其中EXOFS_ROOT_ID为0x10002. (由函数mkfs_one()调用create ()实现)
5.
在设备表对象中写入设备表。具体步骤如下:
a)
调用create()创建设备表对象,设备表对象的对象号为{pid, EXOFS_DEVTABLE_ID},其中EXOFS_DEVTABLE_ID为0x10001。
b)
调用_make_credential()以不做检验方式初始化设备表对象的权能,也就是创建证书。
c)
根据先前输入的参数创建并初始化设备表结构体struct exofs_device_table,并将其写入到设备表对象中取。
6.
在超级块对象中写入超级块是通过调用函数write_super()实现的,该函数调用_make_credential()以不做检验方式初始化超级块对象的权能,也就是创建证书。初始化超级块数据结构struct exofs_fscb,并将其写入超级块对象。
7.
在根目录对象中写入根目录信息是通过调用函数write_rootdir()实现的,该函数调用_make_credential()以不做检验方式初始化根目录对象的权能,也就是创建证书。初始化根目录项数据结构struct exofs_dir_entry,并将其写入根目录对象。
8.
在根目录项对象中写入根inodes是通过调用函数set_inode()实现的,inode信息是以结构体struct exofs_fcb进行描述。set_inode()函数具体步骤如下:
a)
初始化一个struct
exofs_fcb结构体
b)
调用函数osd_start_request()分配一个osd请求。
c)
调用_make_credential()创建证书,其实就是调用osd_sec_init_nosec_doall_caps()以不做检验方式(no security)初始化根对象权能。
d)
调用osd_req_set_attributes()获取对象属性(实际只是进行编码)
e)
将根inode(结构体struct exofs_fcb)以属性列表的形式添加到osd请求中。
f)
调用kick_it()执行请求,调用osd_end_request()释放资源。
内核态源码:
磁盘上的超级块:
- //.common.h
- struct exofs_fscb {
- __le64 s_nextid; /* Highest object ID used *///已被使用的最大到对象ID
- __le64 s_numfiles; /* Number of files on fs *///文件系统上的文件数
- __le32 s_version; /* == EXOFS_FSCB_VER *///超级块版本,直接为EXOFS_FSCB_VER
- __le16 s_magic; /* Magic signature */ //文件系统魔数
- __le16 s_newfs; /* Non-zero if this is a new fs *///如果这是一个新的文件系统,则非零
- /* From here on it's a static part, only written by mkexofs */
- __le64 s_dev_table_oid; /* Resurved, not used */ //保留
- __le64 s_dev_table_count; /* == 0 means no dev_table *///如果没有设备列表,则为0
- } __packed;
在挂载到时候,调用exofs_fill_super()(super.c )从osd设备上读取上述信息来初始化内存中的超级块描述符struct
super_block。
超级块操作:
- // ./super.c
- static const struct super_operations exofs_sops = {
- .alloc_inode = exofs_alloc_inode, //对于一个给定的超级块,创建并初始化一个新的inode对象
- .destroy_inode = exofs_destroy_inode, //释放一个给定的超级块
- .write_inode = exofs_write_inode, //当某个inode为脏(被修改了),就有VFS进行调用。这里如果是日志文件系统,则调用该函数进行日志的更新?
- .evict_inode = exofs_evict_inode, //从磁盘删除一个inode
- .put_super = exofs_put_super, //在卸载过程中由VFS调用来释放一个给定到超级块对象,调用者必须持有s_lock锁
- .write_super = exofs_write_super, //用一个给定的超级块更新磁盘上的超级块,VFS利用其来将内存中的超级块同步到磁盘,调用者必须持有s_lock锁
- .sync_fs = exofs_sync_fs, //将文件系统元数据同步到磁盘(osd设备上)
- .statfs = exofs_statfs, //由VFS调用来获取文件系统的统计数据并保存与结构体struct statfs中
- };
这里有部分域为空,则调用后有可能是调用一个通用的操作函数,或者什么也不做,这个取决于具体操作。
在挂载到时候,调用exofs_fill_super()(super.c )来初始化超级块操作。
磁盘上的inode结构:
- // ./common.h
- struct exofs_fcb {
- __le64 i_size; /* Size of the file */ //文件大小
- __le16 i_mode; /* File mode */ //文件访问模式
- __le16 i_links_count; /* Links count */ //文件链接数
- __le32 i_uid; /* Owner Uid */ //文件拥有者id
- __le32 i_gid; /* Group Id */ //文件组id
- __le32 i_atime; /* Access time */ //文件访问时间
- __le32 i_ctime; /* Creation time */ //文件创建时间
- __le32 i_mtime; /* Modification time */ //文件修改时间
- __le32 i_flags; /* File flags (unused for now)*/ //文件系统标志
- __le32 i_generation; /* File version (for NFS) */ //文件版本(对应于NFS)
- __le32 i_data[EXOFS_IDATA]; /* Short symlink names and device #s */ //对应的osd设备id
- };
当文件被访问时,也就是调用open()函数时,通过读取磁盘上的inode结构初始化内存中的inode结构体 struct inode。
具体一点就是根据索引节点号获取该索引节点时,调用函数exofs_get_inode()(inode.c),或者将内存中的索引节点刷新到磁盘时,调用函数exofs_update_inode()(inode.c)
inode操作:
目录类型的inode操作:
- // ./namei.c
- const struct inode_operations exofs_dir_inode_operations = {
- .create = exofs_create,
- //由open(),creat()系统调用调用,对一个给定的初始化访问模式创建一个新的inode
- .lookup = exofs_lookup,
- //根据由dentry给定的文件名找到对应的inode
- .link = exofs_link,
- //由link()系统调用调用,对一个给定的名字创建硬链接
- .unlink = exofs_unlink,
- //由unlink()系统调用调用,删除该链接对应到inode
- .symlink = exofs_symlink,
- //由symlink()系统调用调用,创建一个符号链接
- .mkdir = exofs_mkdir,
- //由mkdir()系统调用调用,创建目录
- .rmdir = exofs_rmdir,
- //删除目录,由rmdir()系统调用调用
- .mknod = exofs_mknod,
- //创建特殊文件如设备文件、有名管道和socket,由mknod()系统调用调用
- .rename = exofs_rename, //改名
- .setattr = exofs_setattr,
- //在inode被修改后,由notify_change()来通知一个”change event”
- };
在从磁盘读取一个inode后,需要根据类型初始化对其的操作集,调用exofs_iget()(inode.c)。
当创建一个目录时,同时也会创建一个内存inode并初始化对其的操作集,调用exofs_mkdir()(namei.c)
特殊inode节点对应的操作:
- // namei.c
- const struct inode_operations exofs_special_inode_operations = {
- .setattr = exofs_setattr,
- //在inode被修改后,由notify_change()来通知一个”change event”
- };
在从磁盘读取一个inode后,需要根据类型初始化对其的操作集,调用exofs_iget()(inode.c)。
普通文件类型的inode操作:
- // ./file.c
- const struct inode_operations exofs_file_inode_operations = {
- .setattr = exofs_setattr,
- //在inode被修改后,由notify_change()来通知一个”change event”
- };
在从磁盘读取一个inode后,需要根据类型初始化对其的操作集,调用exofs_iget()(inode.c)。
当创建一个普通文件时,同时也会创建一个内存inode并初始化对其的操作集,调用exofs_create()(namei.c)
符号链接inode对应的操作:
- // symlink.c
- const struct inode_operations exofs_symlink_inode_operations = {
- .readlink = generic_readlink,
- //将符号链接指向的文件的文件名拷贝到缓冲区,由readlink()系统调用调用
- .follow_link = page_follow_link_light,
- //将符号链接转换为其所指的inode,并将inode信息保存于nameidata中。
- .put_link = page_put_link,
- //在follow_link()调用之后,调用该函数进行清除工作。
- };
在从磁盘读取一个inode后,需要根据类型初始化对其的操作集,调用exofs_iget()(inode.c)。
当创建一个普通文件时,同时也会创建一个内存inode并初始化对其的操作集,调用exofs_symlink()(namei.c)
磁盘上的目录项
- // common.h
- struct exofs_dir_entry {
- __le64 inode_no; /* inode number */ //索引节点数
- __le16 rec_len; /* directory entry length */ //目录项长度
- u8 name_len; /* name length */ //名字长度
- u8 file_type; /* umm...file type */ //文件类型
- char name[EXOFS_NAME_LEN]; /* file name */ //文件名
- };
文件操作:
目录类型的文件的操作:
- // ./dir.c
- const struct file_operations exofs_dir_operations = {
- .llseek = generic_file_llseek,
- .read = generic_read_dir,
- .readdir = exofs_readdir,
- };
在从磁盘读取一个inode后,需要根据类型初始化对其所对应文件的操作集,调用exofs_iget()(inode.c)。
当创建一个普通文件时,同时也会创建一个内存inode并初始化对其所对应的文件的操作集,调用exofs_mkdir()(namei.c)
普通文件的操作:
- // ./file.c
- const struct file_operations exofs_file_operations = {
- .llseek = generic_file_llseek,
- .read = do_sync_read,
- .write = do_sync_write,
- .aio_read = generic_file_aio_read,
- .aio_write = generic_file_aio_write,
- .mmap = generic_file_mmap,
- .open = generic_file_open,
- .release = exofs_release_file,
- .fsync = exofs_file_fsync,
- .flush = exofs_flush,
- .splice_read = generic_file_splice_read,
- .splice_write = generic_file_splice_write,
- };
在从磁盘读取一个inode后,需要根据类型初始化对其所对应的文件的操作集,调用exofs_iget()(inode.c)。
当创建一个普通文件时,同时也会创建一个内存inode并初始化对其所对应的文件的操作集,调用exofs_create()(namei.c)
特定文件系统类型描述:
- // ./super.c
- static struct file_system_type exofs_type = {
- .owner = THIS_MODULE,
- .name = "exofs",
- .mount = exofs_mount, //文件系统挂载函数
- .kill_sb = generic_shutdown_super, //终止访问超级块
- };
在文件系统模块插入初始化调用register_filesystem()对该文件系统注册。在文件系统模块删除时调用unregister_filesystem()对该文件系统注销。