Linux内核研究:我的虚拟文件系统(linux)

发表于:2007-07-04来源:作者:点击数: 标签:
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

  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_FOLLOW|LOOKUP_POSITIVE, &nd);
    kfree(name);
    
    if (path_init("/hello", LOOKUP_FOLLOW|LOOKUP_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);
  }

原文转自:http://www.ltesting.net