Linux内核研究:我的虚拟文件系统(linux)
hello.c代码:
#include "hello.h"
struct inode * hello_get_inode(struct super_block *, int, struct hello_dir_entry *);
int hello_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
printk("hello_readdir\n");
struct hello_dir_entry * de;
unsigned int ino;
int i;
struct inode *inode = filp->f_dentry->d_inode;
ino = inode->i_ino;
de = (struct hello_dir_entry *) inode->u.generic_ip;
if (!de)
return -EINVAL;
i = filp->f_pos;
switch (i) {
case 0:
if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
return 0;
i++;
filp->f_pos++;
/* fall through */
case 1:
if (filldir(dirent, "..", 2, i,
filp->f_dentry->d_parent->d_inode->i_ino,
DT_DIR) < 0)
return 0;
i++;
filp->f_pos++;
/* fall through */
default:
de = de->subdir;
i -= 2;
for (;;) {
if (!de)
return 1;
if (!i)
break;
de = de->next;
i--;
}
do {
if (filldir(dirent, de->name, de->namelen, filp->f_pos,
de->low_ino, de->mode >> 12) < 0)
return 0;
filp->f_pos++;
de = de->next;
} while (de);
}
return 1;
}
int hello_d_revalidate(struct dentry *res, int i){printk("d_revalidate\n");return 0;}
int hello_d_hash(struct dentry *res, struct qstr *name){printk("d_hash\n");return 0;}
int hello_d_compare(struct dentry *res, struct qstr *name, struct qstr *old)
{printk("d_compare\n");return 0;}
int hello_d_delete(struct dentry *res){printk("d_delete\n");return 0;}
void hello_d_release(struct dentry *res){printk("d_release\n");}
void hello_d_iput(struct dentry *res, struct inode *inode){printk("d_iput\n");}
struct dentry_operations hello_lookup_dops = {
/*d_revalidate:
hello_d_revalidate,
d_hash:
hello_d_hash,
d_compare:
hello_d_compare,*/
d_delete:
hello_d_delete,
d_release:
hello_d_release,
/*d_iput:
hello_d_iput*/
};
struct dentry *hello_lookup(struct inode * dir, struct dentry *dentry)
{
struct inode *inode;
struct hello_dir_entry * de;
int error;
error = -ENOENT;
inode = NULL;
de = (struct hello_dir_entry *) dir->u.generic_ip;
if (de) {
for (de = de->subdir; de ; de = de->next) {
if (!de || !de->low_ino)
continue;
if (de->namelen != dentry->d_name.len)
continue;
if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
int ino = de->low_ino;
error = -EINVAL;
inode = hello_get_inode(dir->i_sb, ino, de);
break;
}
}
}
if (inode) {
dentry->d_op = &hello_lookup_dops;
d_add(dentry, inode);
return NULL;
}
return ERR_PTR(error);
}
/************************************************************************************************************/
static struct inode_operations hello_root_inode_operations = {
lookup:
hello_lookup,
};
static struct file_operations hello_file_operations = {
readdir:
hello_readdir,
};
struct hello_dir_entry hello_root = {
low_ino:
HELLO_ROOT_INO,
namelen:
5,
name:
"/hello",
mode:
S_IFDIR | S_IRUGO | S_IXUGO,
nlink:
2,
hello_iops:
&hello_root_inode_operations,
hello_fops:
&hello_file_operations,
parent:
&hello_root,
};
struct inode * hello_get_inode(struct super_block * sb, int ino,
struct hello_dir_entry * de)
{
printk("hello_get_inode\n");
struct inode * inode;
de_get(de);
inode = iget(sb, ino);
if (!inode)
goto out_fail;
inode->u.generic_ip = (void *) de;
if (de) {
if (de->mode) {
inode->i_mode = de->mode;
inode->i_uid = de->uid;
inode->i_gid = de->gid;
}
if (de->size)
inode->i_size = de->size;
if (de->nlink)
inode->i_nlink = de->nlink;
if (de->owner)
__MOD_INC_USE_COUNT(de->owner);
if (de->hello_iops)
inode->i_op = de->hello_iops;
if (de->hello_fops)
inode->i_fop = de->hello_fops;
}
out:
return inode;
out_fail:
de_put(de);
goto out;
}
/***********************************************************************************************************/
void d_instantiate(struct dentry *entry, struct inode * inode)
{
printk("d_instantiate\n");
if (!list_empty(&entry->d_alias)) BUG();
spin_lock(&dcache_lock);
if (inode)
list_add(&entry->d_alias, &inode->i_dentry);
entry->d_inode = inode;
spin_unlock(&dcache_lock);
}
struct dentry * d_alloc_root(struct inode * root_inode)
{
struct dentry *res = NULL;
printk("d_alloc_root\n");
if (root_inode) {
res = d_alloc(NULL, &(const struct qstr) { "/", 1, 0 });
if (res) {
res->d_sb = root_inode->i_sb;
res->d_parent = res;
d_instantiate(res, root_inode);
}
}
return res;
}
void force_delete(struct inode *inode)
{
printk("force_delete\n");
struct hello_dir_entry *de = inode->u.generic_ip;
if (atomic_read(&inode->i_count) == 1)
inode->i_nlink = 0;
if (atomic_dec_and_test(&de->count))
printk("hello_root.count: %d\n", atomic_read(&de->count));
}
static void hello_delete_inode(struct inode *inode)
{
printk("hello_delete_inode\n");
struct hello_dir_entry *de = inode->u.generic_ip;
inode->i_state = I_CLEAR;
/*if (de) {
if (de->owner)
__MOD_DEC_USE_COUNT(de->owner);
de_put(de);
}*/
}
static void hello_read_inode(struct inode * inode)
{
printk("hello_read_inode\n");
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
}
static int hello_statfs(struct