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 super_block *sb, struct statfs *buf) { printk("hello_statfs\n"); return 0; } void hello_write_super(struct super_block *s) { printk("write_super\n"); } static struct super_operations hello_sops = { read_inode: hello_read_inode, put_inode: force_delete, delete_inode: hello_delete_inode, write_super: hello_write_super, /*statfs: hello_statfs,*/ }; struct dentry_operations hello_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 super_block *hello_read_super(struct super_block *s, void *data, int silent) { printk("hello_read_super\n"); struct inode * root_inode; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = 0; s->s_op = &hello_sops; root_inode = hello_get_inode(s, HELLO_ROOT_INO, &hello_root); if (!root_inode) goto out_no_root; s->s_root = d_alloc_root(root_inode); if (!s->s_root) goto out_no_root; s->s_root->d_op = &hello_dops; return s; out_no_root: printk("hello_read_super: get root inode failed\n"); iput(root_inode); return NULL; } hello.h 代碼: #include #include #include #include #include #include #include #include #include #include #include #define HELLO_ROOT_INO 1 typedef int (read_hello_t)(char *page, char **start, off_t off, int count, int *eof, void *data); typedef int (write_hello_t)(struct file *file, const char *buffer, unsigned long count, void *data); typedef int (get_info_t)(char *, char **, off_t, int); struct hello_dir_entry { unsigned short low_ino; unsigned short namelen; const char *name; mode_t mode; nlink_t nlink; uid_t uid; gid_t gid; unsigned long size; struct inode_operations * hello_iops; struct file_operations * hello_fops; get_info_t *get_info; struct module *owner; struct hello_dir_entry *next, *parent, *subdir; void *data; read_hello_t *read_hello; write_hello_t *write_hello; atomic_t count; /* use count */ int deleted; /* delete flag */ kdev_t rdev; }; extern struct hello_dir_entry hello_root; extern struct dentry *hello_lookup(struct inode *, struct dentry *); extern int hello_misc_init(void); extern struct super_block *hello_read_super(struct super_block *, void *, int); extern void de_put(struct hello_dir_entry *); extern struct hello_dir_entry * de_get(struct hello_dir_entry *); extern int hello_readdir(struct file *, void *, filldir_t); hello_entry.c 代碼: #include "hello.h" static struct inode_operations hello_dir_inode_operations = { lookup: hello_lookup, }; struct hello_dir_entry * de_get(struct hello_dir_entry *de) { printk("de_get\n"); if (de) atomic_inc(&de->count); return de; } void inline free_hello_entry(struct hello_dir_entry *de) { printk("free_hello_entry\n"); kfree(de); } void de_put(struct hello_dir_entry *de) { printk("de_put\n"); if (de) { if (!atomic_read(&de->count)) { printk("de_put: entry %s already free!\n", de->name); return; } if (atomic_dec_and_test(&de->count)) free_hello_entry(de); } } static ssize_t hello_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) { struct inode * inode = file->f_dentry->d_inode; char *page; ssize_t n; char *start; struct hello_dir_entry * dp; dp = (struct hello_dir_entry *) inode->u.generic_ip; if (!(page = (char*) __get_free_page(GFP_KERNEL))) return -ENOMEM; n = dp->read_hello(page, &start, *ppos,0, NULL, NULL); copy_to_user(buf, page, n); free_page((unsigned long) page); return n; } static ssize_t hello_file_write(struct file * file, const char * buffer, size_t count, loff_t *ppos) { struct inode *inode = file->f_dentry->d_inode; struct hello_dir_entry * dp; dp = (struct hello_dir_entry *) inode->u.generic_ip; if (!dp->write_hello) return -EIO; /* FIXME: does this routine need ppos? probably... */ return dp->write_hello(file, buffer, count, dp->data); } static loff_t hello_file_lseek(struct file * file, loff_t offset, int origin) { long long retval; switch (origin) { case 2: offset += file->f_dentry->d_inode->i_size; break; case 1: offset += file->f_pos; } retval = -EINVAL; if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) { if (offset != file->f_pos) { file->f_pos = offset; file->f_reada = 0; } retval = offset; } return retval; } static struct file_operations hello_file_operations = { llseek: hello_file_lseek, read: hello_file_read, write: hello_file_write, }; static int hello_register(struct hello_dir_entry * dir, struct hello_dir_entry * dp) { printk("hello_register\n"); dp->low_ino = 2; dp->next = dir->subdir; dp->parent = dir; dir->subdir = dp; if (S_ISDIR(dp->mode)) { if (dp->hello_iops == NULL) { dp->hello_fops = NULL; dp->hello_iops = &hello_dir_inode_operations; } dir->nlink++; } else if (S_ISREG(dp->mode)) { if (dp->hello_fops == NULL) dp->hello_fops = &hello_file_operations; } return 0; } static struct hello_dir_entry *hello_create(struct hello_dir_entry **parent, const char *name, mode_t mode, nlink_t nlink) { printk("hello_create\n"); struct hello_dir_entry *ent = NULL; const char *fn = name; int len; len = strlen(name); *parent = &hello_root; ent = kmalloc(sizeof(struct hello_dir_entry) + len + 1, GFP_KERNEL); if (!ent) goto out; memset(ent, 0, sizeof(struct hello_dir_entry)); memcpy(((char *) ent) + sizeof(struct hello_dir_entry), fn, len + 1); ent->name = ((char *) ent) + sizeof(*ent); ent->namelen = len; ent->mode = mode; ent->nlink = nlink; out: return ent; } struct hello_dir_entry *create_hello_entry(const char *name, mode_t mode, struct hello_dir_entry *parent) { printk("create_hello_entry\n"); struct hello_dir_entry *ent; nlink_t nlink; if (S_ISDIR(mode)) { if ((mode & S_IALLUGO) == 0) mode = S_IRUGO S_IXUGO; nlink = 2; } else { if ((mode & S_IFMT) == 0) mode = S_IFREG; if ((mode & S_IALLUGO) == 0) mode = S_IRUGO; nlink = 1; } ent = hello_create(&parent,name,mode,nlink); if (ent) { if (hello_register(parent, ent) < 0) { kfree(ent); ent = NULL; } } return ent; } static inline struct hello_dir_entry *hello_read_entry(const char *name, mode_t mode, struct hello_dir_entry *base, read_hello_t *read_hello, void * data) { printk("hello_dir_entry\n"); struct hello_dir_entry *res=create_hello_entry(name,mode,base); if (res) { res->read_hello=read_hello; res->write_hello = NULL; res->data=data; } return res; } /************************************************************************************************************/ int read_hello(char *page, char **start, off_t off, int count, int *eof, void *data) { strcpy(page, "hello world!"); return 13; } int hello_misc_init(void) { printk("hello_misc_init\n"); struct hello_dir_entry *err; err = hello_read_entry("zhang", 0, NULL, read_hello, NULL); return !err; } mount.c 代碼: #include "hello.h" extern int graft_tree(struct vfsmount *, struct nameidata *); static DECLARE_FSTYPE(hello_fs_type, "hello", hello_read_super, FS_SINGLE); struct vfsmount *mnt; int hello_root_init(void) { struct nameidata nd; int err; err = register_filesystem(&hello_fs_type); printk("register_filesystem\n"); if (err) return err; mnt = kern_mount(&hello_fs_type); printk("kern_mount\n"); err = PTR_ERR(mnt); if (IS_ERR(mnt)) goto out; hello_misc_init(); MOD_DEC_USE_COUNT; /* int (*path_lookup)(const char *, unsigned, struct nameidata *) = (void*)0xc0152ac0; int (*path_init)(const char *, unsigned int, struct nameidata *) = (void*)0xc0152b00; int (*path_walk)(const char *, struct nameidata *) = (void*)0xc0152940; char * name; int (*graft_tree)(struct vfsmount *mnt, struct nameidata *nd) = (void*)0xc015fc30; name = kmalloc(10, GFP_KERNEL); strcpy(name, "/hello"); err = path_lookup(name, LOOKUP_FOLLOWLOOKUP_POSITIVE, &nd); kfree(name); if (path_init("/hello", LOOKUP_FOLLOWLOOKUP_POSITIVE, &nd)) err = path_walk("/hello", &nd); if (err) goto out; err = graft_tree(mnt, &nd); */ char *name, *type; name = kmalloc(10, GFP_KERNEL); type = kmalloc(10, GFP_KERNEL); strcpy(name, "/hello"); strcpy(type, "hello"); long (*do_mount)(char *, char *, char *, unsigned long, void *) = (void*)0xc01603f0;/*0xc0166ad0;*/ do_mount(NULL, name, type, 0, NULL); kfree(name); kfree(type); /*if (err) goto out; */ return 0; out: mntput(mnt); unregister_filesystem(&hello_fs_type); return err; } int init_module(void) { printk("init_module\n"); hello_root_init(); return 0; } void cleanup_module() { printk("cleanup_module\n"); mntput(mnt); unregister_filesystem(&hello_fs_type); } Makefile 代碼: CC = gcc CFLAGS = -O -Wall -D__KERNEL__ -DMODULE #INCLUDEDIR = /usr/local/linux-2.4.22/include INCLUDEDIR = /usr/src/linux-2.4.20-8/include CFLAGS += -I$(INCLUDEDIR) myfs.o: mount.o hello_entry.o hello.o $(LD) -m elf_i386 -r -o myfs.o mount.o hello_entry.o hello.o mount.o: mount.c hello.h /usr/include/linux/version.h $(CC) $(CFLAGS) -c mount.c hello_entry.o: hello_entry.c hello.h /usr/include/linux/version.h $(CC) $(CFLAGS) -c hello_entry.c hello.o: hello.c hello.h /usr/include/linux/version.h $(CC) $(CFLAGS) -c hello.c 測試程序read.c 代碼: #include #include #include #include int main() { int fp; char buf[11]; buf[10] = 0; int i; if ((fp = open("/hello/zhang", O_RDWR)) == 0) { printf("Could not opened!\n"); return -1; } else printf("File open ok!\n"); read(fp, buf, 13); printf("%s\n", buf); close(fp); }