前言
之前找到过一篇关于简单文件系统驱动的,但那篇文章是直接划了一块内存作为设备,我这里改动了一下,使用一个文件镜像作为设备
本文代码是适配linux-6.6内核的,github上还有适配4.15内核的分支
github链接
说明
功能实现
挂载: 支持
创建文件夹: 不支持 & 没打算做
(所以arcofs文件系统挂载之后是平坦——的, 只有一层路径, 哈哈
创建文件: 支持
创建链接: 不支持 (没实现symlink
删除文件: 支持
写文件: 当前仅支持1次性写入1kb以内数据, 再次写入同一文件会提示 No space left on device
(目标是支持单个文件正常的存储最多8kb数据
实现的过时的write方法, write_iter还没看明白
读文件: 当前仅支持读取1024kb以内的内容
实现的过时的read方法, read_iter还没看明白
实现细节
block size: 1024byte
super block:
魔数、inode总数、空闲inode数、块总数、空闲块总数
arcofs inode
i_mode、i_size、i_block[8]、char filename[12]
8个i_block都是直接块,没搞间接块,所以文件大小最多支持8kb
没搞dentry结构,文件名直接放在inode里,所以限定12字节
arcofs inode设定为64byte, 还有12字节的padding
文件系统的系统块划分:
第0个block, 不使用
第1个block, 用作super block
第2个block, 用作block bytemap
第3个block, 用作inode bytemap
第4个block, 用作inode table
(为了方便编程, 我直接使用一个unsigned char类型来标注一个块是否被占用, 所以是 byte map
数据块管理
简化了ext2文件系统中间接、双重间接、三重间接的管理方式,arcofs的每个inode仅管理8个直接块
dentry结构
没有
arcofs没有设立专门的dentry结构,也没打算管理目录;文件名以最长11个字节的形式保存在inode中
arcofs
下面是文件系统驱动的代码arcofs.c
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/parser.h>
#include <linux/random.h>
#include <linux/buffer_head.h>
#include <linux/exportfs.h>
#include <linux/vfs.h>
#include <linux/seq_file.h>
#include <linux/mount.h>
#include <linux/log2.h>
#include <linux/quotaops.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/compiler.h>
#define ARCOFS_VERSION "0.1"
#define ARCOFS_BLOCK_SIZE 1024
#define ARCOFS_MAGIC 0x27266673 // 0x6673 is the ascii of 'fs'
#ifndef __CHECKER__
extern void *__stack_chk_guard;
extern void __stack_chk_fail(void);
#endif
/*
* #1
* arcofs文件系统结构体
*/
// VFS的super block
// s_fs_info(指向一个sbi对象)
// s_as(指向arcofs的super block结构)
struct arcofs_super_block {
unsigned int s_magic;
int s_inodes_count;
int s_free_inodes_count;
int s_blocks_count;
int s_free_blocks_count;
char pad[1004];
};
struct arcofs_inode {
/*00*/ int i_mode;
/*04*/ int i_size;
/*08*/ int i_block[8];
/*40*/ char filename[12];
/*52*/ char pad[12];
};
struct arcofs_bytemap {
unsigned char idx[1024];
};
struct arcofs_sb_info {
int version;
struct arcofs_super_block *s_as;
};
/*
* #2
* 函数声明
*/
int arcofs_writepage(struct page *page, struct writeback_control *wbc);
static int arcofs_readpage(struct file *file, struct page *page);
static sector_t arcofs_bmap(struct address_space *mapping, sector_t block);
int arcofs_get_block(struct inode * inode, sector_t block, struct buffer_head *bh, int create);
void arcofs_set_inode(struct inode *inode, dev_t rdev);
struct inode *arcofs_new_inode(const struct inode *dir, umode_t mode, const char *name);
static int arcofs_mknod(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev);
static int arcofs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl);
static struct dentry *arcofs_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags);
static int arcofs_unlink(struct inode * dir, struct dentry *dentry);
//static int arcofs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); // ubuntu16内核不一致,暂不实现
static int arcofs_readdir(struct file *file, struct dir_context *ctx);
static ssize_t arcofs_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
static ssize_t arcofs_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
static int arcofs_statfs(struct dentry *dentry, struct kstatfs *buf);
struct arcofs_inode* arcofs_raw_inode(struct super_block *sb, int ino, struct buffer_head **bh);
struct inode *arcofs_iget(struct super_block *sb, unsigned long ino);
/*
* #3
* 操作结构声明
*/
// 地址空间操作结构
static const struct address_space_operations arcofs_aops = {
// .readpage = arcofs_readpage,
.writepage = arcofs_writepage,
// .write_begin = arcofs_write_begin,
// .write_end = generic_write_end,
.bmap = arcofs_bmap,
};
// dir操作结构
const struct inode_operations arcofs_dir_inode_operations = {
.create = arcofs_create,
.lookup = arcofs_lookup,
// .link = arcofs_link,
.unlink = arcofs_unlink,
// .symlink = arcofs_symlink,
// .mkdir = arcofs_mkdir,
// .rmdir = arcofs_rmdir,
.mknod = arcofs_mknod,
// .rename = arcofs_rename,
// .getattr = arcofs_getattr, // 这个指针类型不匹配, 看下是不是4.15内核改了(果然!ubuntu16内核里头文件不一样, 这个不管了
// .tmpfile = arcofs_tmpfile,
};
const struct file_operations arcofs_dir_operations = {
.llseek = generic_file_llseek,
.read = generic_read_dir,
.iterate_shared = arcofs_readdir,
.fsync = generic_file_fsync,
};
// file操作结构
const struct inode_operations arcofs_file_inode_operations = {
// .setattr = arcofs_setattr,
// .getattr = arcofs_getattr,
};
const struct file_operations arcofs_file_operations = {
.llseek = generic_file_llseek,
.read = arcofs_read,
.write = arcofs_write,
// .read_iter = generic_file_read_iter,
// .write_iter = generic_file_write_iter, // 这两个太高级了, 没玩明白, 先注释掉
.mmap = generic_file_mmap,
.open = dquot_file_open,
.fsync = generic_file_fsync,
// .splice_read = generic_file_splice_read,
};
// 超级块操作结构
static const struct super_operations arcofs_sops = {
// .alloc_inode = arcofs_alloc_inode,
// .destroy_inode = arcofs_destroy_inode,
// .write_inode = arcofs_write_inode,
// .evict_inode = arcofs_evict_inode,
// .put_super = arcofs_put_super,
.statfs = arcofs_statfs,
// .remount_fs = arcofs_remount,
};
/*
* #4
* 操作结构回调函数实现
*/
// ##4.1 aops方法实现
int arcofs_writepage(struct page *page, struct writeback_control *wbc)
{
return block_write_full_page(page, arcofs_get_block, wbc);
}
static int arcofs_readpage(struct file *file, struct page *page)
{
// return block_read_full_page(page, arcofs_get_block);
return 0;
}
static sector_t arcofs_bmap(struct address_space *mapping, sector_t block)
{
return generic_block_bmap(mapping,block, arcofs_get_block);
}
int arcofs_get_block(struct inode * inode, sector_t block, struct buffer_head *bh, int create)
{
printk("arco-fs: try get block %lld\n", block);
map_bh(bh, inode->i_sb, block);
return 0;
}
// ##4.2 dir方法实现
void arcofs_set_inode(struct inode *inode, dev_t rdev)
{
// 判断inode的i_mode,挂载不同的操作结构
if (S_ISREG(inode->i_mode)) {
printk("arco-fs: inode type file\n");
inode->i_op = &arcofs_file_inode_operations;
inode->i_fop = &arcofs_file_operations;
inode->i_mapping->a_ops = &arcofs_aops;
}
else if (S_ISDIR(inode->i_mode)) {
printk("arco-fs: inode type dir\n");
inode->i_op = &arcofs_dir_inode_operations;
inode->i_fop = &arcofs_dir_operations;
inode->i_mapping->a_ops = &arcofs_aops;
}
else {
printk("arco-fs: unsupport inode type 0x%x\n", inode->i_mode);
init_special_inode(inode, inode->i_mode, rdev);
}
}
struct inode *arcofs_new_inode(const struct inode *dir, umode_t mode, const char *name)
{
int i;
struct super_block *sb = dir->i_sb;
struct arcofs_sb_info *sbi = sb->s_fs_info;
struct inode *inode = new_inode(sb);
struct buffer_head* inode_bytemap_block;
inode_bytemap_block = sb_bread(sb, 3); // block number of inode bytemap
unsigned char *inode_bytemap_arr = (unsigned char*)inode_bytemap_block->b_data;
// 在inode bytemap中 找到一个空闲的inode
for (i = 0; i < sbi->s_as->s_inodes_count; i++) {
printk("arco-fs: inode[%d] state=%d\n", i, inode_bytemap_arr[i]);
if (inode_bytemap_arr[i] == 1) {
printk("arco-fs: find inode[%d] free\n", i);
inode_bytemap_arr[i] = 2;
inode->i_ino = i + 1; // ino号从1而不是从0开始
break;
}
}
inode->i_blocks = 0;
inode->i_mode = S_IFREG; // create出来的一律是file, mkdir出来的才是dir
// 在磁盘中创建一个arcofs inode
struct buffer_head* inode_table_block;
inode_table_block = sb_bread(sb, 4); // block number of inode bytemap
struct arcofs_inode *inode_table_arr = (struct arcofs_inode*)inode_table_block->b_data;
inode_table_arr[i].i_mode = S_IFREG;
strcpy(inode_table_arr[i].filename, name); // 用
// 没有加入dentry的动作
// insert_inode_hash(inode);
mark_inode_dirty(inode);
mark_buffer_dirty(inode_bytemap_block);
mark_buffer_dirty(inode_table_block);
return inode;
}
static int arcofs_add_nondir(struct dentry *dentry, struct inode *inode)
{
// ext2这里还做了其他操作,但我没看懂
d_instantiate(dentry, inode);
return 0;
}
// umode_t是unsigned short类型
static int arcofs_mknod(struct mnt_idmap *idmap, struct inode * dir, struct dentry *dentry, umode_t mode, dev_t rdev)
{
int error = 0;
struct inode *inode;
if (!old_valid_dev(rdev))
return -EINVAL;
printk("arco-fs: try touch file name (%s)\n", dentry->d_name.name);
inode = arcofs_new_inode(dir, mode, dentry->d_name.name);
if (inode) {
arcofs_set_inode(inode, rdev);
mark_inode_dirty(inode);
error = arcofs_add_nondir(dentry, inode);
}
return error;
}
static int arcofs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
{
return arcofs_mknod(idmap, dir, dentry, mode, 0);
}
ino_t arcofs_inode_by_name(struct inode* dir, struct dentry *dentry)
{
int i, ino = 0;
struct super_block* sb = dir->i_sb;
struct arcofs_sb_info* sbi = sb->s_fs_info;
struct buffer_head* bh;
printk("arco-fs: execute arcofs_inode_by_name\n");
// 在inode表里直接找
bh = sb_bread(sb, 4);
struct arcofs_inode* inode_table_arr = (struct arcofs_inode*)bh->b_data;
for (i = 0; i < sbi->s_as->s_inodes_count; i++) {
printk("arco-fs: match [%s] [%s]", inode_table_arr[i].filename, dentry->d_name.name);
if (strcmp(inode_table_arr[i].filename, dentry->d_name.name) == 0) {
ino = i + 1;
printk("arco-fs: file[%s] ino=%d", dentry->d_name.name, ino);
brelse(bh);
return ino;
}
}
return 0;
}
static struct dentry *arcofs_lookup(struct inode* dir, struct dentry *dentry, unsigned int flags)
{
struct inode * inode = NULL;
ino_t ino;
ino = arcofs_inode_by_name(dir, dentry);
if (ino) {
inode = arcofs_iget(dir->i_sb, ino);
if (IS_ERR(inode))
return ERR_CAST(inode);
}
d_add(dentry, inode);
return NULL;
}
static void arcofs_free_file(struct inode *inode, struct arcofs_inode *raw_inode, int rewrite)
{
int i;
struct super_block *sb = inode->i_sb;
struct buffer_head *bh2, *bh3;
// 清除标志位
raw_inode->i_mode = 0;
raw_inode->i_size = 0;
inode->i_size = 0;
// 释放block bytemap
bh2 = sb_bread(sb, 2);
unsigned char* block_bytemap_arr = (unsigned char*)bh2->b_data;
for (i = 0; i < 8; i++) {
if (raw_inode->i_block[i] == 0) break;
block_bytemap_arr[raw_inode->i_block[i]] = 1;
raw_inode->i_block[i] = 0;
printk("arco-fs: block[%d] once occupied, now free\n", raw_inode->i_block[i]);
}
mark_buffer_dirty(bh2);
if (rewrite) return; // 如果只是重写文件调用的释放资源, 不释放inode bytemap
// 释放inode bytemap
bh3 = sb_bread(sb, 3);
unsigned char* inode_bytemap_arr = (unsigned char*)bh3->b_data;
inode_bytemap_arr[inode->i_ino - 1] = 1;
printk("arco-fs: inode[%lu] once occupied, now free\n", inode->i_ino - 1);
mark_buffer_dirty(bh3);
}
static int arcofs_unlink(struct inode * dir, struct dentry *dentry)
{
printk("arco-fs: execute unlink\n");
struct inode *inode = d_inode(dentry);
struct buffer_head *bh;
struct arcofs_inode *raw_inode = arcofs_raw_inode(inode->i_sb, inode->i_ino, &bh);
// 释放文件占用的资源
arcofs_free_file(inode, raw_inode, 0);
// 减少vfs层面的引用?不懂
inode_dec_link_count(inode);
return 0;
}
int rdflag = 1;
static int arcofs_readdir(struct file *file, struct dir_context *ctx)
{
int i;
rdflag = !rdflag;
printk("arco-fs: execute readdir rdflag=%d\n", rdflag);
struct buffer_head* bh;
struct inode* inode = file_inode(file);
struct super_block* sb = inode->i_sb;
struct arcofs_sb_info *sbi = sb->s_fs_info;
// 已经读过是1, return(我暂时没明白这里为什么会读两次
if (rdflag) return 0;
// 读出inode表里的filename,arcofs没有专门设置dentry区
bh = sb_bread(sb, 4); // block number of inode bytemap
struct arcofs_inode *inode_table_arr = (struct arcofs_inode*)bh->b_data;
// 并不一定是连续分布的, 所以每个都要过一遍
for (i = 0; i < sbi->s_as->s_inodes_count; i++) {
if (inode_table_arr[i].i_mode != 0) {
printk("arco-fs: inode[%d] filename:%s\n", i, inode_table_arr[i].filename);
unsigned l = strnlen(inode_table_arr[i].filename, sizeof(((struct arcofs_inode*)NULL)->filename));
// 下面的参数i+1就是文件的inode号
if (!dir_emit(ctx, inode_table_arr[i].filename, l, i + 1, DT_UNKNOWN)) {
return 0;
}
}
ctx->pos += sizeof(((struct arcofs_inode*)NULL)->filename);
}
brelse(bh);
return 0;
}
static ssize_t arcofs_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
printk("arco-fs: execute read. len=%ld f_flags=0x%x ppos=%lld\n", len, filp->f_flags, *ppos);
int i, read_len, read_offset = 0;
char pot[ARCOFS_BLOCK_SIZE * 8];
char *kbuf = pot;
struct inode* inode = filp->f_mapping->host;
struct super_block* sb = inode->i_sb;
struct arcofs_inode* raw_inode;
struct buffer_head* bh;
// 查找inode的iblock
raw_inode = arcofs_raw_inode(inode->i_sb, inode->i_ino, &bh);
// 判断文件是否读完
if (*ppos == raw_inode->i_size) {
printk("arco-fs: arrive file end\n");
return 0;
}
// 查找这个inode的每个block, 把数据拷贝到kbuf中
for (i = 0; i < 8; i++) {
if (raw_inode->i_block[i] == 0) {
printk("arco-fs: this file hasn't alloc i_block[%d]\n", i);
break;
}
else {
// 计算本次要读的字节数
read_len = (raw_inode->i_size >= (i + 1) * 1024) ? 1024 : raw_inode->i_size % 1024;
printk("arco-fs: file i_size=%d i_block[0]=%d read_len=%d\n", raw_inode->i_size, raw_inode->i_block[0], read_len);
bh = sb_bread(sb, raw_inode->i_block[i]);
memcpy(kbuf + read_offset, bh->b_data, read_len);
read_offset += read_len;
}
}
printk("arco-fs: read buf:%s\n", kbuf);
if (copy_to_user(buf, kbuf, raw_inode->i_size)) {
return -EFAULT;
}
*ppos += raw_inode->i_size;
return raw_inode->i_size;
}
int arcofs_alloc_block(struct inode* inode)
{
int i, block_number = 0;
struct super_block* sb = inode->i_sb;
struct arcofs_sb_info *sbi = sb->s_fs_info;
struct buffer_head* bh;
bh = sb_bread(sb, 2);
unsigned char *block_bytemap_arr = (unsigned char*)bh->b_data;
// 查找block bytemap, 分配一块没使用的block
for (i = 5; i < sbi->s_as->s_blocks_count; i++) {
if (block_bytemap_arr[i] == 1) {
block_bytemap_arr[i] = 2;
block_number = i;
printk("arco-fs: find block %d free\n", block_number);
break;
}
}
mark_buffer_dirty(bh);
return block_number;
}
static ssize_t arcofs_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
printk("arco-fs: execute write. len=%ld f_flags=0x%x\n", len, filp->f_flags);
int i, r, alloc_block = 5, remain_len = len, write_len, block_offset = 0, write_offset = 0;
char pot[ARCOFS_BLOCK_SIZE * 8];
char *kbuf = pot;
struct inode* inode = filp->f_mapping->host;
struct super_block* sb = inode->i_sb;
struct buffer_head *bh, *bhx;
struct arcofs_inode* raw_inode = arcofs_raw_inode(inode->i_sb, inode->i_ino, &bh);
if (len > 8 * 1024) return -ENOSPC;
if (copy_from_user(kbuf, buf, len)) return -EFAULT;
printk("arco-fs: write buf:%s\n", kbuf);
// 如果是覆盖写入模式, 需要截断文件长度(直接调用释放文件资源函数
if (!(filp->f_flags & O_APPEND)) {
printk("arco-fs: cover write mode\n");
int tmp_mode = raw_inode->i_mode;
arcofs_free_file(inode, raw_inode, 1);
raw_inode->i_mode = tmp_mode;
}
// 逐个块写入
for(r = 0; remain_len > 0; r++) {
write_len = remain_len >= 1024 ? 1024 : remain_len;
printk("arco-fs: write round %d write_len=%d\n", r, write_len);
if (raw_inode->i_size + write_len > 8 * 1024) {
printk("arco-fs: exceed file max length, exit\n");
return -ENOSPC;
}
// 如果未分配块
if (raw_inode->i_size == 0) {
alloc_block = arcofs_alloc_block(inode);
raw_inode->i_block[0] = alloc_block;
printk("arco-fs: alloc block[%d]\n", alloc_block);
}
// 如果某个块刚好用完(需要更新文件长度
else if (raw_inode->i_size % ARCOFS_BLOCK_SIZE == 0) {
for (i = 0; i < 8; i++) {
if (raw_inode->i_block[i] == 0) {
printk("arco-fs: use i_block[%d]\n", i);
alloc_block = arcofs_alloc_block(inode);
raw_inode->i_block[i] = alloc_block;
break;
}
}
}
else {
alloc_block = raw_inode->i_block[raw_inode->i_size / 1024];
block_offset = raw_inode->i_size % 1024;
// 如果最后一个block剩余的空间不足以满足当次的写入
printk("arco-fs: block_offset(%d) + write_len(%d) = %d\n", block_offset, write_len, block_offset + write_len);
if (block_offset + write_len > 1024) write_len = (1024 - block_offset);
}
remain_len -= write_len;
// write_block:
if (alloc_block == 0) {
printk("arco-fs: find block err\n");
return -ENOSPC;
}
bhx = sb_bread(sb, alloc_block);
memcpy(bhx->b_data + block_offset, kbuf + write_offset, write_len);
// 更新inode
inode->i_size += write_len;
printk("arco-fs: round %d raw_inode->i_size=%d write_len=%d remain_len=%d\n", r, raw_inode->i_size, write_len, remain_len);
raw_inode->i_size += write_len;
// 标志位处理
write_offset += write_len;
block_offset = 0;
// 标记dirty
mark_buffer_dirty(bh);
mark_buffer_dirty(bhx);
}
return len;
}
// ##4.3 file方法实现
// 暂无
// ##4.4 super block方法实现
static int arcofs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
struct arcofs_sb_info *sbi = sb->s_fs_info;
buf->f_type = sb->s_magic;
buf->f_bsize = sb->s_blocksize;
buf->f_blocks = sbi->s_as->s_blocks_count;
buf->f_bfree = sbi->s_as->s_free_blocks_count;
buf->f_bavail = buf->f_bfree;
buf->f_files = (sbi->s_as->s_inodes_count - sbi->s_as->s_free_inodes_count);
buf->f_ffree = sbi->s_as->s_free_inodes_count;
return 0;
}
/*
* #5
* 文件系统挂载函数实现
* fill_super相关
*/
struct arcofs_inode* arcofs_raw_inode(struct super_block *sb, int ino, struct buffer_head **bh)
{
int block;
ino -= 1;
block = 4; // inode表所在的块号
*bh = sb_bread(sb, block);
if (!*bh) {
printk("arco-fs: Unable to read inode block\n");
return NULL;
}
return (struct arcofs_inode*)((*bh)->b_data + (ino * sizeof(struct arcofs_inode))); // 加块内偏移地址
}
struct inode *arcofs_iget(struct super_block *sb, unsigned long ino)
{
struct inode *inode;
struct buffer_head *bh;
struct arcofs_inode *raw_inode;
inode = iget_locked(sb, ino);
if (!inode) {
printk("arco-fs: iget_locked failed\n");
return ERR_PTR(-ENOMEM);
}
// 获取原始arcofs inode
raw_inode = arcofs_raw_inode(inode->i_sb, inode->i_ino, &bh);
// 拼装VFS inode
inode->i_size = raw_inode->i_size; // i_size是文件大小
inode->i_mode = raw_inode->i_mode; // i_mode是文件类型
arcofs_set_inode(inode, 0);
return inode;
}
static int arcofs_fill_super(struct super_block *s, void *data, int silent)
{
int err = -1;
struct arcofs_sb_info *sbi;
struct inode *root_inode;
struct buffer_head *bh, *bh2, *bh3;
struct arcofs_super_block *as;
sbi = kzalloc(sizeof(struct arcofs_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
s->s_fs_info = sbi;
// 设置sb->s_blocksize
if (!sb_set_blocksize(s, ARCOFS_BLOCK_SIZE))
goto out_bad_hblock;
if (!(bh = sb_bread(s, 1)))
goto out_bad_sb;
if (!(bh2 = sb_bread(s, 2)))
goto out_bad_map;
if (!(bh3 = sb_bread(s, 3)))
goto out_bad_map;
// 把上一步读取出的块作为arcofs super_block
as = (struct arcofs_super_block*) bh->b_data;
sbi->s_as = as;
s->s_magic = as->s_magic;
// 判断block是否足够
// 注册super block操作结构
s->s_op = &arcofs_sops;
// 获取根目录的inode(inode号从1开始)
root_inode = arcofs_iget(s, 1);
if (IS_ERR(root_inode)) {
err = PTR_ERR(root_inode);
goto out_no_root;
}
// dmake root
s->s_root = d_make_root(root_inode);
if (!s->s_root)
goto out_no_root;
printk("arco-fs: fill super seems ok\n");
return 0;
out_bad_hblock:
printk("arco-fs: blocksize too small for device\n");
out_bad_sb:
printk("arco-fs: unable to read superblock\n");
out_bad_map:
printk("arco-fs: unable to read block and inode map\n");
out_no_root:
printk("arco-fs: no root error\n");
return err;
}
static struct dentry *arcofs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_bdev(fs_type, flags, dev_name, data, arcofs_fill_super);
}
static struct file_system_type arcofs_fs_type = {
.owner = THIS_MODULE,
.name = "arcofs",
.mount = arcofs_mount,
.kill_sb = kill_block_super,
.fs_flags = FS_REQUIRES_DEV,
};
MODULE_ALIAS_FS("arcofs");
static int __init init_arcofs_fs(void)
{
int ret;
printk("arco-fs: version:%s\n", ARCOFS_VERSION);
ret = register_filesystem(&arcofs_fs_type);
return ret;
}
static void __exit exit_arcofs_fs(void)
{
unregister_filesystem(&arcofs_fs_type);
}
MODULE_AUTHOR("ARCO");
MODULE_DESCRIPTION("ARCO Filesystem");
MODULE_LICENSE("GPL");
module_init(init_arcofs_fs);
module_exit(exit_arcofs_fs);
mkarcofs
下面是制作文件系统驱动的工具的代码mkarcofs.c
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<fcntl.h>
#include<errno.h>
#define ARCOFS_BLOCK_SIZE 1024
#define ARCOFS_MAGIC 0x27266673 // 0x6673 is the ascii of 'fs'
/*
* description:
* as ext2, reserved first block for boot partition
* block 1: super block
* block 2: block bitmap
* block 3: inode bitmap
* block 4: inode table
* block 5+ data area
*/
struct arcofs_super_block {
unsigned int s_magic;
int s_inodes_count;
int s_free_inodes_count;
int s_blocks_count;
int s_free_blocks_count;
char pad[1004];
};
struct arcofs_inode {
/*00*/ int i_mode;
/*04*/ int i_size;
/*08*/ int i_block[8];
/*40*/ char filename[12];
/*52*/ char pad[12];
};
struct arcofs_bytemap {
unsigned char idx[1024];
};
int main(int argc, char* argv[])
{
char filename[256];
/* 合法校验 */
if (argc != 2) {
printf("mkarcofs: arg num error\n");
return -1;
}
strcpy(filename, argv[1]);
struct stat st;
if (stat(filename, &st) != 0) {
printf("mkarcofs: file %s is not exist\n", filename);
return -1;
}
// 判断是否为文件
if (!(st.st_mode & S_IFREG)) {
printf("mkarcofs: %s is not file", filename);
return -1;
}
// 计算文件大小是否能进行格式化(最少16kb)
printf("mkarcofs: file size=%ldbyte\n", st.st_size);
if (st.st_size * 8 < 16 * 1024) {
printf("mkarcofs: file size too small, can't make arcofs\n");
return -1;
}
/* 使用mmap映射文件到内存 */
int fd, maplen = st.st_size, block_num;
void* start = NULL;
fd = open(filename, O_RDWR);
if (fd <= 0) {
printf("mkarcofs: open %s failed\n", filename);
return -1;
}
start = (char*)mmap(NULL, maplen, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (start <= 0) {
printf("mkarcofs: mmap failed errno:%s\n", strerror(errno));
}
// 跳过reserved块
start += ARCOFS_BLOCK_SIZE;
/* 计算可分配的block数量 */
block_num = st.st_size / 1024 - 1;
printf("mkarcofs: block_num=%d\n", block_num);
/* 格式化super_block */
struct arcofs_super_block *sb = malloc(sizeof(struct arcofs_super_block));
sb->s_magic = ARCOFS_MAGIC;
sb->s_inodes_count = (ARCOFS_BLOCK_SIZE / sizeof(struct arcofs_inode));
sb->s_free_inodes_count = sb->s_inodes_count - 2; // .和..
sb->s_blocks_count = block_num - 4;
sb->s_free_blocks_count = block_num - 4;
memset(sb->pad, 0, sizeof(sb->pad));
printf("start addr:%p\n", start);
printf("sb addr:%p\n", sb);
printf("sizeof sb=%ld\n", sizeof(struct arcofs_super_block));
memcpy(start, sb, sizeof(struct arcofs_super_block));
start += ARCOFS_BLOCK_SIZE;
/* 格式化block bitmap */
memset(start, 1, ARCOFS_BLOCK_SIZE); // memset按uchar填充
struct arcofs_bytemap *blockmap = (struct arcofs_bytemap*)start;
blockmap->idx[0] = 2;
blockmap->idx[1] = 2;
start += ARCOFS_BLOCK_SIZE;
/* 格式化inode bitmap */
memset(start, 1, ARCOFS_BLOCK_SIZE);
struct arcofs_bytemap *inodemap = (struct arcofs_bytemap*)start;
inodemap->idx[0] = 2;
inodemap->idx[1] = 2;
start += ARCOFS_BLOCK_SIZE;
/* 格式化inode table */
// 创建.目录inode
memset(start, 0, ARCOFS_BLOCK_SIZE);
struct arcofs_inode *node_dot = malloc(sizeof(struct arcofs_inode));
node_dot->i_mode = S_IFDIR;
strcpy(node_dot->filename, ".");
memset(node_dot->i_block, 0, sizeof(node_dot->i_block));
memset(node_dot->pad, 0, sizeof(node_dot->pad));
memcpy(start, node_dot, sizeof(struct arcofs_inode));
start += sizeof(struct arcofs_inode);
// 创建..目录inode
memset(start, 0, ARCOFS_BLOCK_SIZE);
struct arcofs_inode *node_dotdot = malloc(sizeof(struct arcofs_inode));
node_dotdot->i_mode = S_IFDIR;
strcpy(node_dotdot->filename, "..");
memset(node_dotdot->i_block, 0, sizeof(node_dotdot->i_block));
memset(node_dotdot->pad, 0, sizeof(node_dotdot->pad));
memcpy(start, node_dotdot, sizeof(struct arcofs_inode));
start += sizeof(struct arcofs_inode);
munmap(start, maplen);
return 0;
}
使用
示例脚本如下:
# 功能测试脚本
dd if=/dev/zero of=arco.img bs=1024 count=16
./mkarcofs arco.img
mkdir mnt
umount mnt/
echo "8 8 8 8" > /proc/sys/kernel/printk
md5sum arcofs.ko
rmmod arcofs.ko
insmod arcofs.ko
mount -o loop -t arcofs arco.img mnt
编译
编译脚本
更换内核路径、编译器
KDIR := /home/kirin7/kernel/linux-6.6.57
CC = aarch64-kirin7-linux-gnu-gcc
ccflags-y := -std=gnu99 -Wno-error
obj-m=arcofs.o
PWD=$(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules
$(CC) mkarcofs.c -o mkarcofs
md5sum mkarcofs arcofs.ko
clean:
make -C $(KDIR) M=$(PWD) clean
编译说明
使用gcc9以下的版本编译内核时,需要关闭STACKPROTECTOR配置项,否则插入驱动时会报错找不到stack_chk…的符号
问题
4.15版本运行正常,6.6版本重新挂载后有死锁问题