话说文件系统——一个简单的文件系统(一)
linux的文件系统很庞大,之前看过、学过、哭过、也闹过,差点就撒娇了,哎,只怪功底不够,硬是没有看明白,心想小僧此生与它无缘了,
又无高人,迷津终没有得到指点。时间就这么平静而有飞逝着,突然有一天无意当中看到一本叫
《linux内核探秘:深入解析文件系统和设备驱动的框架与设计》书,里面有一个最简单的文件系统(aufs)的实现,又激起我研究linux文件系统
的欲望。发现aufs的实现仅仅有两百多行,正由于它的简单,分析起来容易,同时也涉及到了linux文件系统的各个方面,分析之后,对文件系统
的基本概念有了最基本的认识,为后面的学习打下了基础,在此把整个学习的过程做个记录,如果对大家有帮助,我就很荣幸了。
回顾来看,其实之前没有弄明白的主要原因在于着急,没有从基础的、简单的开始,一上来就直接看源代码,分析sysfs这些成熟的文件系统,
由于sysfs本身跟其他的东西错综盘旋在一起,增加了很多的难度,这样连续几天就会失去学习的信心,从而放弃,所谓心急吃不了热豆腐,欲速
则不达啊。正因为此,我们最开始先看一下aufs的实现,自己编译一波,感受一下,有个感性的认识,而不一上来就讲原理,我们要循序渐进,
下面就是aufs的实现。
aufs文件系统的实现源码:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/init.h>
#include <linux/namei.h>
#include <linux/cred.h>
#include <linux/mount.h>
//每个文件系统需要一个MAGIC number
#define AUFS_MAGIC 0x64668735
//aufs文件系统的挂载点
static struct vfsmount *aufs_mount;
//根据创建的aufs文件系统的 super_block创建具体的inode结构体
static struct inode *aufs_get_inode(struct super_block *sb, int mode,
dev_t dev)
{
struct inode *inode = new_inode(sb);
if (inode) {
inode->i_mode = mode;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
default:
init_special_inode(inode, mode, dev);
break;
case S_IFREG:
printk("create a file \n");
break;
case S_IFDIR:
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
printk("creat a dir file \n");
inode->__i_nlink++;
break;
}
}
return inode;
}
//把创建的inode和dentry结构体连接起来
static int aufs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
{
struct inode * inode;
int error = -EPERM;
if (dentry->d_inode)
return -EEXIST;
inode = aufs_get_inode(dir->i_sb, mode, dev);
if (inode) {
d_instantiate(dentry, inode);
dget(dentry);
error = 0;
}
return error;
}
static int aufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int res;
res = aufs_mknod(dir, dentry, mode | S_IFDIR, 0);
if (!res) {
dir->__i_nlink++;
}
return res;
}
static int aufs_create(struct inode *dir, struct dentry *dentry, int mode)
{
return aufs_mknod(dir, dentry, mode | S_IFREG, 0);
}
//根据父dentry、mode、name创建子dentry
static int aufs_create_by_name(const char *name, mode_t mode,
struct dentry *parent, struct dentry **dentry)
{
int error = 0;
if (!parent) {
if (aufs_mount && aufs_mount->mnt_sb) {
parent = aufs_mount->mnt_sb->s_root;
}
}
if (!parent) {
printk("Ah! can not find a parent!\n");
return -EFAULT;
}
*dentry = NULL;
mutex_lock(&parent->d_inode->i_mutex);
*dentry = lookup_one_len(name, parent, strlen(name));
if (!IS_ERR(dentry)) {
if ((mode & S_IFMT) == S_IFDIR)
error = aufs_mkdir(parent->d_inode, *dentry, mode);
else
error = aufs_create(parent->d_inode, *dentry, mode);
} else
error = PTR_ERR(dentry);
mutex_unlock(&parent->d_inode->i_mutex);
return error;
}
//在aufs文件系统中创建文件
struct dentry *aufs_create_file(const char *name, mode_t mode,
struct dentry *parent, void *data,
struct file_operations *fops)
{
struct dentry *dentry = NULL;
int error;
printk("aufs: creating file '%s'", name);
error = aufs_create_by_name(name, mode, parent, &dentry);
if (error) {
dentry = NULL;
goto exit;
}
if (dentry->d_inode) {
if (data)
dentry->d_inode->i_private = data;
if (fops)
dentry->d_inode->i_fop = fops;
}
exit:
return dentry;
}
//在aufs文件系统中创建一个文件夹
struct dentry *aufs_create_dir(const char *name, struct dentry *parent)
{
return aufs_create_file(name, S_IFDIR | S_IRWXU | S_IRUGO, parent, NULL, NULL);
}
static int enabled = 1;
//对应于打开的aufs文件的读取方法
static ssize_t aufs_file_read(struct file *fle, char __user *buf, size_t nbytes, loff_t *ppos)
{
char *s = enabled ? "aufs read enabled\n" : "aufs read disabled\n";
dump_stack();
return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s));
}
//对应于打开的aufs文件的写入方法
static ssize_t aufs_file_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
int res = *buffer - '0';
if (res)
enabled = 1;
else
enabled = 0;
return count;
}
//对应具体打开文件的文件操作方式
static struct file_operations aufs_file_operations = {
.read = aufs_file_read,
.write = aufs_file_write,
};
//用于填充aufs的super_block
static int aufs_fill_super(struct super_block *sb, void *data, int silent)
{
static struct tree_descr debug_files[] = {{""}};
return simple_fill_super(sb, AUFS_MAGIC, debug_files);
}
//创建aufs文件系统的对应的根目录的dentry
static struct dentry *aufs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_single(fs_type, flags, data, aufs_fill_super);
}
//初始化aufs文件系统的 file_system_type结构,每个文件系统对应一个这样的结构体,主要用于提供具体文件系统的
//的信息,以及操作的方法
static struct file_system_type aufs_type = {
.name = "aufs",
.mount = aufs_get_sb,
.kill_sb = kill_litter_super,
};
//创建aufs文件系统,同时创建对应的文件夹和文件
static int __init aufs_init(void)
{
int ret;
struct dentry *pslot;
ret = register_filesystem(&aufs_type);
if (ret) {
printk(KERN_ERR "aufs: cannot register file system\n");
return ret;
}
aufs_mount = kern_mount(&aufs_type);
if (IS_ERR(aufs_mount)) {
printk(KERN_ERR "aufs: cannot mount file system\n");
unregister_filesystem(&aufs_type);
return ret;
}
pslot = aufs_create_dir("woman_star", NULL); //创建woman_star文件系统,返回所创建文件夹的dentry
aufs_create_file("lbb", S_IFREG | S_IRUGO, pslot, NULL, &aufs_file_operations);//在对应的文件夹下,创建具体的文件
aufs_create_file("fbb", S_IFREG | S_IRUGO, pslot, NULL, &aufs_file_operations);
aufs_create_file("lj1", S_IFREG | S_IRUGO, pslot, NULL, &aufs_file_operations);
pslot = aufs_create_dir("man_star", NULL);
aufs_create_file("ldh", S_IFREG | S_IRUGO, pslot, NULL, &aufs_file_operations);
aufs_create_file("lcw", S_IFREG | S_IRUGO, pslot, NULL, &aufs_file_operations);
aufs_create_file("jw", S_IFREG | S_IRUGO, pslot, NULL, &aufs_file_operations);
return 0;
}
//卸载aufs文件系统
static void __exit aufs_exit(void)
{
kern_unmount(aufs_mount);
unregister_filesystem(&aufs_type);
aufs_mount = NULL;
}
module_init(aufs_init);
module_exit(aufs_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("This is a simple module");
MODULE_VERSION("Ver 0.1");
下面编译的Makefile文件:
ifneq ($(KERNELRELEASE),)
obj-m := aufs.o
else
KDIR := /lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(shell pwd) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order
endif
程序编译后,我们通过insmod 命令加载模块,然后执行如下操作。
1.在根目录下创建一个目录:
mkdir aufs
2. 挂载文件系统:
mount -t aufs none aufs/
3. 列出文件系统的内容:
ls
通过查看看到了“woman_star”和“man_star”两个目录。同时里面又有对应的文件。