romfs 文件系统
网上有很多关于romfs文件系统的介绍,文件接口简单 ,只读文件系统
之前对linux文件系统不了解,只知道是管理文件的系统,之前只停留在数据管理概念阶段 ,现在看看代码研究了下 大致思想,未完。。
我找了下 linux/fs/里面比较简单的一个文件系统 romfs。因为是只读 那么省掉好多事情,数据文件和文件信息 是按照链表方式分布的。
链表头(super block)-》文件头1(包含下一个文件的地址,文件类型,本长度,校验信息,文件名字)+文件数据
文件2 地址被上一个文件1头里面保存--》文件头2(包含下一个文件的地址,文件类型,本长度,校验信息,文件名字)+文件数据
.。。。。。。。。。。。。。。。。。。文件n+1 地址被上一个文件n头里面保存--》文件n+1(包含下一个文件的地址,文件类型,本长度,校验信息,文件名字)+文件数据
我们把上面个的文件头x就是信息 称作 物理 inode,linux fs的inode 包含好多属性,因为不是所有的文件系统 只需要这些新就够了,其中涉及 读写权限 文件所属 修改时间。。。很多信息。
我们来看下 romfs 在linux 下面的代码理解,我们侧重分析下
register_filesystem(&romfs_fs_type);
static struct file_system_type romfs_fs_type = {
.owner = THIS_MODULE,
.name = "romfs",
.mount = romfs_mount,
.kill_sb = romfs_kill_sb,
.fs_flags = FS_REQUIRES_DEV,
};
/*
* get a superblock for mounting
*/
static struct dentry *romfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data)
{
struct dentry *ret = ERR_PTR(-EINVAL);
#ifdef CONFIG_ROMFS_ON_MTD ///先以一种存储类型为例
ret = mount_mtd(fs_type, flags, dev_name, data, romfs_fill_super);
#endif
#ifdef CONFIG_ROMFS_ON_BLOCK
if (ret == ERR_PTR(-EINVAL))
ret = mount_bdev(fs_type, flags, dev_name, data,
romfs_fill_super);
#endif
return ret;
}
/*
* fill in the superblock romf的超级块信息比较少,提取关键信息 给linux 文件系统
*/
static int romfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct romfs_super_block *rsb;
struct inode *root;
unsigned long pos, img_size;
const char *storage;
size_t len;
int ret;
sb->s_maxbytes = 0xFFFFFFFF;
sb->s_magic = ROMFS_MAGIC;
sb->s_flags |= SB_RDONLY | SB_NOATIME; //SB_RDONLY 只读属性
sb->s_op = &romfs_super_ops;
#ifdef CONFIG_ROMFS_ON_MTD
/* Use same dev ID from the underlying mtdblock device */
if (sb->s_mtd)
sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, sb->s_mtd->index);
#endif
/* read the image superblock and check it */
rsb = kmalloc(512, GFP_KERNEL);
if (!rsb)
return -ENOMEM;
sb->s_fs_info = (void *) 512;
ret = romfs_dev_read(sb, 0, rsb, 512);
if (ret < 0)
goto error_rsb;
img_size = be32_to_cpu(rsb->size);
if (sb->s_mtd && img_size > sb->s_mtd->size)
goto error_rsb_inval;
sb->s_fs_info = (void *) img_size;
if (rsb->word0 != ROMSB_WORD0 || rsb->word1 != ROMSB_WORD1 ||
img_size < ROMFH_SIZE) {
if (!silent)
pr_warn("VFS: Can't find a romfs filesystem on dev %s.\n",
sb->s_id);
goto error_rsb_inval;
}
if (romfs_checksum(rsb, min_t(size_t, img_size, 512))) {
pr_err("bad initial checksum on dev %s.\n", sb->s_id);
goto error_rsb_inval;
}
storage = sb->s_mtd ? "MTD" : "the block layer";
len = strnlen(rsb->name, ROMFS_MAXFN);
if (!silent)
pr_notice("Mounting image '%*.*s' through %s\n",
(unsigned) len, (unsigned) len, rsb->name, storage);
kfree(rsb);
rsb = NULL;
/* find the root directory */
pos = (ROMFH_SIZE + len + 1 + ROMFH_PAD) & ROMFH_MASK;
root = romfs_iget(sb, pos);
if (IS_ERR(root))
return PTR_ERR(root);
sb->s_root = d_make_root(root);
if (!sb->s_root)
return -ENOMEM;
return 0;
。。。。。
}
第1行 register_filesystem 注册为文件系统
第5行 文件系统名字
第6行 挂在这个文件系统时候的行为
第38行 mount 的关键行为获取文件信息 超级快
第51行 romfs 超级快的 ops 接口
第56行 填充 s_dev (设备号信息)和上面 romfs_super_ops 一块打开操作文件用
第64行 读取512字节超级块信息(实际上没这么大,多读取点,后面在提取关键信息)
第75行 检查 romfs 超级快 标记字符信息 看下对不对
第83行 检查 romfs 超级快 校验信息 看下对不对(只是简单就和计算sun)
第90行 检查 romfs 超级快查找 文件名信息(超级块里面的文件名是卷宗名)
第99行 接下来找到第一个文件的文件信息了->根目录文件。
第101行 找到根文件的 物理inode 并填充关键信息到新linux 文件inode
第105行 inode转换到 根路径
devtmpfs 文件系统
突然想到 dev下面的那些设备哪里来的,看了看发现
device_register---》device_add(dev)--》devtmpfs_create_node(dev)
这个devtmpfs 也是个文件系统 没有放在kerne/fs 目录下面,在driver/base/devtmpfs.c
wake_up_process(thread);
wait_for_completion(&req.done);
thread这个进程 在devtmpfs_init ——》thread = kthread_run(devtmpfsd, &err, "kdevtmpfs")
static int devtmpfsd(void *p)
{
char options[] = "mode=0755";
int *err = p;
*err = ksys_unshare(CLONE_NEWNS);
if (*err)
goto out;
*err = ksys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options);
if (*err)
goto out;
ksys_chdir("/.."); /* will traverse into overmounted root */
ksys_chroot(".");
complete(&setup_done);
while (1) {
spin_lock(&req_lock);
while (requests) {
struct req *req = requests;
requests = NULL;
spin_unlock(&req_lock);
while (req) {
struct req *next = req->next;
req->err = handle(req->name, req->mode,
req->uid, req->gid, req->dev);
complete(&req->done);
req = next;
}
spin_lock(&req_lock);
}
__set_current_state(TASK_INTERRUPTIBLE);
spin_unlock(&req_lock);
schedule();
}
return 0;
out:
complete(&setup_done);
return *err;
}
req->name =
主要看这里吧
while (req) {
struct req *next = req->next;
req->err = handle(req->name, req->mode, //req->mode 前面设置过
req->uid, req->gid, req->dev);
complete(&req->done);
req = next;
}
handle_create(name, mode, uid, gid, dev);
vfs_mknod(d_inode(path.dentry), dentry, mode, dev->devt)
vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
vfs_mknod2(NULL, dir, dentry, mode, dev)
dir->i_op->mknod(dir, dentry, mode, dev)
ramfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
d_instantiate(dentry, inode);
__d_instantiate(entry, inode); // 目录项高速缓存种 建立 entry 和inode 联系
目录项:目录项是描述文件的逻辑属性,只存在于内存中,并没有实际对应的磁盘上的描述,更确切的说是存在于内存的目录项缓存,为了提高查找性能而设计。注意不管是文件夹还是最终的文件,都是属于目录项,所有的目录项在一起构成一颗庞大的目录树
所以说 devtmpfs_create_node 会自动 创建 dentry inode
kthread_run(devtmpfsd, &err, "kdevtmpfs") --》 devtmpfs_create_node -》wake_up_process(thread) --》devtmpfsd-》handle-》--》handle_create
其中handle_create 会调用 (dentry = kern_path_create(AT_FDCWD, nodename, &path, 0))得到dentry
handle_create -》vfs_mknod-》 ramfs_mknod-》ramfs_get_inode-》inode = new_inode(sb) 得到inode init_special_inode(inode, mode, dev) inode 和dev_t dev建立联系。
所有 device_add ,既创建了 文件节点 inode ,也增加了 文件路径信息 dentry,所有如果一个设备添加成功会在 /dev 目录下面 出现对应文件。
如果说我们用mknod 命令 执行 mknod dev/zero c 1 5 估计从 vfs_mknod 开始。
前面 init_special_inode 把inode 和设备号 关联起来, 如果此时open设备会发生如下图所示流程,所有就完成了 ,驱动注册编写了设备驱动,用户通过文件名,使用设备,调用了驱动里面的驱动文件相关动作。
PS:上图是网上搜到的 不是本人制作的,再次声明