int dazukofs_dev_init(void)
{
int err;
dev_t devt;
err = dazukofs_init_events();
if (err)
goto error_out1;
err = alloc_chrdev_region(&devt, 0, 2 + GROUP_COUNT, DEVICE_NAME); //动态分配10个设备
if (err)
goto error_out2;
dev_major = MAJOR(devt); //主
dev_minor_start = MINOR(devt); //次
dazukofs_class = class_create(THIS_MODULE, DEVICE_NAME); // 在/dev 下创建设备
if (IS_ERR(dazukofs_class)) {
err = PTR_ERR(dazukofs_class);
goto error_out3;
}
err = dazukofs_ctrl_dev_init(dev_major, dev_minor_start,
dazukofs_class);
if (err)
goto error_out4;
err = dazukofs_ign_dev_init(dev_major, dev_minor_start + 1,
dazukofs_class);
if (err)
goto error_out5;
dev_minor_end = dazukofs_group_dev_init(dev_major,
dev_minor_start + 2,
dazukofs_class);
if (dev_minor_end < 0) {
err = dev_minor_end;
goto error_out6;
}
return 0;
error_out6:
dazukofs_ign_dev_destroy(dev_major, dev_minor_start + 1,
dazukofs_class);
error_out5:
dazukofs_ctrl_dev_destroy(dev_major, dev_minor_start, dazukofs_class);
error_out4:
class_destroy(dazukofs_class);
error_out3:
unregister_chrdev_region(MKDEV(dev_major, dev_minor_start),
2 + GROUP_COUNT);
error_out2:
dazukofs_destroy_events();
error_out1:
return err;
}
在这注册三个类型的字符设备ign,ctrl,dazudofs.*,如进入dazukofs_ctrl_dev_init:
int dazukofs_ctrl_dev_init(int dev_major, int dev_minor,
struct class *dazukofs_class)
{
int err = 0;
struct device *dev;
/* setup cdev for control */
cdev_init(&ctrl_cdev, &ctrl_fops); //申请dev结构体,cdev_init函数中使用通过参数传进来的struct file_operations结构体指针对struct cdev的ops域进行初始化,所以在函数cdev_init调用之后不需要再对struct cdev的ops域进行初始化。
ctrl_cdev.owner = THIS_MODULE;
err = cdev_add(&ctrl_cdev, MKDEV(dev_major, dev_minor), 1); //初始化后的struct cdev结构体注册到内核中,就可以访问它了.
if (err)
goto error_out1;
/* create control device */
dev = device_create(dazukofs_class, NULL, MKDEV(dev_major, dev_minor),
NULL, "%s.ctrl", DEVICE_NAME);
if (IS_ERR(dev)) {
err = PTR_ERR(dev);
goto error_out2;
}
return 0;
error_out2:
cdev_del(&ctrl_cdev);
error_out1:
return err;
}
在这里创建设备文件dazudofs.ctrl分配主,次设备号,及对该设备文件相关的操作:
static const struct file_operations ctrl_fops = {
.owner = THIS_MODULE,
.open = dazukofs_ctrl_open,
.release = dazukofs_ctrl_release,
.read = dazukofs_ctrl_read,
.write = dazukofs_ctrl_write,
};
其他二个类型的设备文件注册创建方法一样,也就不多说了.
static ssize_t dazukofs_ctrl_read(struct file *file, char __user *buffer,
size_t length, loff_t *pos)
{
char *buf = file->private_data;
size_t buflen;
int err;
if (!file->private_data) {
err = dazukofs_get_groups(&buf); //分配空间
if (err)
return err;
file->private_data = buf;
}
buflen = strlen(buf);
if (*pos >= buflen)
return 0;
if (length > buflen - *pos)
length = buflen - *pos;
if (copy_to_user(buffer, buf + *pos, length))
return -EFAULT;
*pos += length;
return length;
}
static ssize_t dazukofs_ctrl_write(struct file *file,
const char __user *buffer, size_t length,
loff_t *pos)
{
#define DAZUKOFS_MAX_WRITE_BUFFER 32
char tmp[DAZUKOFS_MAX_WRITE_BUFFER];
int match = 0;
int ret = -EINVAL;
int cp_len = length;
if (cp_len >= DAZUKOFS_MAX_WRITE_BUFFER)
cp_len = DAZUKOFS_MAX_WRITE_BUFFER - 1;
if (copy_from_user(tmp, buffer, cp_len))
return -EFAULT;
tmp[cp_len] = 0;
if (!match || (match && ret >= 0)) {
if (process_command(tmp, "del=",
dazukofs_remove_group, 0, &ret) == 0) {
match = 1;
}
}
if (!match || (match && ret >= 0)) {
if (process_command(tmp, "add=",
dazukofs_add_group, 0, &ret) == 0) {
match = 1;
}
}
if (!match || (match && ret >= 0)) {
if (process_command(tmp, "addtrack=",
dazukofs_add_group, 1, &ret) == 0) {
match = 1;
}
}
if (ret >= 0) {
*pos += length;
ret = length;
}
return ret;
}
对dazukofs.ctrl读写操作都在这实现了,,把数据拷贝到用户空间.
write执行,接受用户程序发送的字符串是否与内核字符匹配,作出相应处理(add,remove)。
再转到文件系统:
static struct file_system_type dazukofs_fs_type = {
.owner = THIS_MODULE,
.name = "dazukofs",
.get_sb = dazukofs_get_sb,
.kill_sb = kill_anon_super,
.fs_flags = 0,
};
static int dazukofs_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data,
struct vfsmount *mnt)
{
struct super_block *sb;
int err;
err = get_sb_nodev(fs_type, flags, data, dazukofs_fill_super, mnt); // 真实现超级块方法 if (err)
goto out;
sb = mnt->mnt_sb; //获取挂载点超级块
err = dazukofs_parse_mount_options(data, sb);
if (err)
goto out_abort;
err = dazukofs_read_super(sb, dev_name); //**
if (err)
goto out_abort;
goto out;
out_abort:
dput(sb->s_root);
up_write(&sb->s_umount);
deactivate_super(sb);
out:
return err;
}
真实现超级块方法dazukofs_fill_super在这里实现,超级块分配空间,创建,释放,文件系统状态等操作。注意
dazukofs_read_super函数,普通索引结点的操作放现去判断
static int dazukofs_fill_super(struct super_block *sb, void *data, int silent)
{
struct dazukofs_sb_info *sbi;
struct dentry *root;
static const struct qstr name = { .name = "/", .len = 1 };
struct dazukofs_dentry_info *di;
sbi = kmem_cache_zalloc(dazukofs_sb_info_cachep, GFP_KERNEL);
if (!sbi)
return -ENOMEM;
sb->s_op = &dazukofs_sops; //超级块操作
root = d_alloc(NULL, &name);
if (!root) {
kmem_cache_free(dazukofs_sb_info_cachep, sbi);
return -ENOMEM;
}
sb->s_root = root; //加载根目录
sb->s_root->d_op = &dazukofs_dops;
sb->s_root->d_sb = sb;
sb->s_root->d_parent = sb->s_root;
di = kmem_cache_zalloc(dazukofs_dentry_info_cachep, GFP_KERNEL);
if (!di) {
kmem_cache_free(dazukofs_sb_info_cachep, sbi);
dput(sb->s_root);
return -ENOMEM;
}
set_dentry_private(sb->s_root, di);
set_sb_private(sb, sbi);
return 0;
}
static int dazukofs_read_super(struct super_block *sb, const char *dev_name)
{
struct nameidata nd;
struct dentry *lower_root;
struct vfsmount *lower_mnt;
int err;
memset(&nd, 0, sizeof(struct nameidata));
err = path_lookup(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
if (err)
return err;
lower_root = dget(nd.path.dentry);
lower_mnt = mntget(nd.path.mnt);
if (IS_ERR(lower_root)) {
err = PTR_ERR(lower_root);
goto out_put;
}
if (!lower_root->d_inode) {
err = -ENOENT;
goto out_put;
}
if (!S_ISDIR(lower_root->d_inode->i_mode)) {
err = -EINVAL;
goto out_put;
}
// sb = mmt->sb
set_lower_sb(sb, lower_root->d_sb); //设置sb
sb->s_maxbytes = lower_root->d_sb->s_maxbytes; //填充文件大小上限
set_lower_dentry(sb->s_root, lower_root, lower_mnt); //设置dentry
err = dazukofs_interpose(lower_root, sb->s_root, sb, 0);
if (err)
goto out_put;
goto out;
out_put:
dput(lower_root);
mntput(lower_mnt);
out:
path_put(&nd.path);
return err;
}
int dazukofs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
struct super_block *sb, int already_hashed)
{
struct inode *inode;
struct inode *lower_inode = igrab(lower_dentry->d_inode);
if (!lower_inode)
return -ESTALE;
if (lower_inode->i_sb != get_lower_sb(sb)) {
iput(lower_inode);
return -EXDEV;
}
inode = iget5_locked(sb, (unsigned long)lower_inode,
dazukofs_inode_test, dazukofs_inode_set,
lower_inode);
if (!inode) {
iput(lower_inode);
return -EACCES;
}
if (inode->i_state & I_NEW) {
unlock_new_inode(inode);
/*
* This is a new node so we leave the lower_node "in use"
* and do not call iput().
*/
} else {
/*
* This is not a new node so we decrement the usage count.
*/
iput(lower_inode);
}
if (S_ISLNK(lower_inode->i_mode))
inode->i_op = &dazukofs_symlink_iops; //关联链接操作函数
else if (S_ISDIR(lower_inode->i_mode))
inode->i_op = &dazukofs_dir_iops; //关联结点操作函数
if (S_ISDIR(lower_inode->i_mode))
inode->i_fop = &dazukofs_dir_fops; //关联文件操作函数
if (special_file(lower_inode->i_mode)) {
init_special_inode(inode, lower_inode->i_mode,
lower_inode->i_rdev);
}
dentry->d_op = &dazukofs_dops; // 填充目录项操作函数
if (already_hashed)
d_add(dentry, inode);
else
d_instantiate(dentry, inode);
fsstack_copy_attr_all(inode, lower_inode);
fsstack_copy_inode_size(inode, lower_inode);
return 0;
}
例如相关文件操作,定义这些,都是通过调vfs层接口来实现的。
const struct file_operations dazukofs_dir_fops = {
.read = dazukofs_read,
.readdir = dazukofs_readdir,
.ioctl = dazukofs_ioctl,
.mmap = dazukofs_mmap,
.open = dazukofs_open,
.flush = dazukofs_flush,
.release = dazukofs_release,
.fsync = dazukofs_fsync,
.fasync = dazukofs_fasync,
.splice_read = generic_file_splice_read,
};
static ssize_t dazukofs_read(struct file *file, char *buf, size_t count,
loff_t *ppos)
{
int err;
struct file *lower_file = get_lower_file(file);
loff_t pos_copy = *ppos;
if (!lower_file->f_op || !lower_file->f_op->read)
return -EINVAL;
err = lower_file->f_op->read(lower_file, buf, count, &pos_copy);
lower_file->f_pos = pos_copy;
*ppos = pos_copy;
if (err >= 0) {
fsstack_copy_attr_atime(file->f_dentry->d_inode,
lower_file->f_dentry->d_inode);
}
memcpy(&(file->f_ra), &(lower_file->f_ra),
sizeof(struct file_ra_state));
return err;
}
最后在文件系统挂载后,在挂载点上建一文件,通过应用程序打印进程号及文件名,应用程序通过读取/proc文件系统下的link对应的文件,如函数:int dazukofs_get_filename(struct dazukofs_access *acc, char *buf, size_t bufsiz)
{
char proc[48];
int ret;
memset(proc, 0, sizeof(proc));
snprintf(proc, sizeof(proc) - 1, "/proc/self/fd/%d", acc->fd);
ret = readlink(proc, buf, bufsiz - 1);
buf[bufsiz - 1] = 0;
if (ret > 0)
buf[ret] = 0;
return ret;
}
见附件。