cramfs patch for bad block (kernel version linux-2.6.32.17) cramfs 坏块补丁

 先前用这个补丁,总是会在有坏块的时候出问题:只好自己研究了

  • <a href="http://blog.csdn.net/joans123/article/details/6601134#reply">http://blog.csdn.net/joans123/article/details/6601134#reply</a>  
  • diff inode.c*

    28,29d27  
    < #include <linux/mtd/mtd.h>   
    < #include <mtd/mtd-abi.h>   
    133d130  
    < //mike change to support bad block: cramfs_read-> cramfs_read_old  
    138c135  
    < static void *cramfs_read_old(struct super_block *sb, unsigned int offset, unsigned int len)  
    ---  
    > static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)  
    213,297d209  
    < //mike added to support bad block  
    < static int get_block_map(struct super_block *sb, int block)   
    < {   
    <       struct cramfs_sb_info *sbi = sb->s_fs_info;   
    <       struct mtd_info *mtd = sbi->mtd;   
    <       int *block_map = (int*)sbi->block_map;   
    <       int blocks = sbi->nblock;   
    <       int pblock = -1;   
    <       int i;   
    <       if(block_map[block]==-1) {   
    <               for(i=0; i<blocks; i++) {   
    <                       if(block_map[i] == -1) {   
    <                               break;   
    <                       }   
    <                       pblock = block_map[i];   
    <               }   
    <               pblock++;   
    <               while(i<=block+4 && i<blocks) {   
    <                       while(mtd->block_isbad(mtd, pblock*mtd->erasesize)) {   
    <                               printk("cramfs: skip bad block %d(page %d)\n", pblock, pblock*32+4096);   
    <                               pblock++;   
    <                       }   
    <                       block_map[i] = pblock;   
    <                       i++;   
    <                       pblock++;   
    <               }   
    <       }   
    <       return block_map[block];   
    < }   
    < static void *cramfs_read_nand(struct super_block *sb, unsigned int offset, unsigned int len)   
    < {   
    <       unsigned i, blocknr, buffer;   
    <       char *data;   
    <       struct cramfs_sb_info *sbi = sb->s_fs_info;   
    <       struct mtd_info *mtd = sbi->mtd;   
    <       unsigned mblock, moffset, pblock, maddr;   
    <       int retv;   
    <       size_t dummy;   
    <       if (!len)   
    <               return NULL;   
    <       blocknr = offset >> PAGE_CACHE_SHIFT;   
    <       for (i = 0; i < READ_BUFFERS; i++) {   
    <               unsigned int blk_offset;   
    <               if (buffer_dev[i] != sb)   
    <                       continue;   
    <               if (blocknr < buffer_blocknr[i])   
    <                       continue;   
    <               blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;   
    <               blk_offset += (offset & (PAGE_CACHE_SIZE-1));   
    <               if (blk_offset + len > BUFFER_SIZE)   
    <                       continue;   
    <               return read_buffers[i] + blk_offset;   
    <       }   
    <       buffer = next_buffer;   
    <       next_buffer = NEXT_BUFFER(buffer);   
    <       buffer_blocknr[buffer] = blocknr;   
    <       buffer_dev[buffer] = sb;   
    <       mblock = offset/mtd->erasesize;   
    <       moffset = (offset & (mtd->erasesize-1))&(~(PAGE_CACHE_SIZE-1));   
    <       offset &= (PAGE_CACHE_SIZE-1);   
    <       pblock = get_block_map(sb, mblock);   
    <       maddr = pblock*mtd->erasesize + moffset;   
    <       data = read_buffers[buffer];   
    <       if( moffset+BUFFER_SIZE <= mtd->erasesize ){   
    <               retv = mtd->read(mtd, maddr, BUFFER_SIZE, &dummy, data);   
    <       }else{   
    <               int read_size;   
    <               read_size = mtd->erasesize-moffset;   
    <               retv = mtd->read(mtd, maddr, read_size, &dummy, data);   
    <               pblock = get_block_map(sb, mblock+1);   
    <               maddr = pblock*mtd->erasesize;   
    <               retv = mtd->read(mtd, maddr, (BUFFER_SIZE-read_size), &dummy, data+read_size);   
    <       }   
    <       return read_buffers[buffer] + offset;   
    < }   
    < static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)   
    < {   
    <       struct cramfs_sb_info *sbi = sb->s_fs_info;   
    <       if(sbi->nand){   
    <               return cramfs_read_nand(sb, offset, len);   
    <       }else{   
    <               return cramfs_read_old(sb, offset, len);   
    <       }   
    < }   
    < //mike added end  
    329,360d240  
    < //mike added to support bad block  
    <       sbi->nand = 0;   
    <       if(MAJOR(sb->s_dev) == MTD_BLOCK_MAJOR)  
    <       {   
    <               struct mtd_info *mtd;   
    <               int *block_map;  
    <               u_int32_t num,  blocks;  
    <               mtd = get_mtd_device(NULL, MINOR(sb->s_dev));   
    <   
    <               if(!mtd)  
    <                       goto not_mtdblock;   
    <   
    <               if(mtd->type != MTD_NANDFLASH)   
    <                       goto not_mtdblock;   
    <   
    <               sbi->mtd = mtd;   
    <               sbi->nand = 1;   
    <   
    <               blocks = (long)(mtd->size) / (long)(mtd->erasesize);   
    <               block_map = (int*)kmalloc(blocks*sizeof(int), GFP_KERNEL);   
    <   
    <               if(block_map == NULL)  
    <                       goto not_mtdblock;  
    <   
    <   
    <               for(num=0; num<blocks; num++)  
    <               {  
    <                       block_map[num] = -1;   
    <               }  
    <   
    <               sbi->block_map = block_map;   
    <               sbi->nblock = blocks;   
    362,365d241  
    <       }  
    <   
    < not_mtdblock:   
    < //mike added end  
    


    官方程序

    /* 
     * Compressed rom filesystem for Linux. 
     * 
     * Copyright (C) 1999 Linus Torvalds. 
     * 
     * This file is released under the GPL. 
     */  
      
    /* 
     * These are the VFS interfaces to the compressed rom filesystem. 
     * The actual compression is based on zlib, see the other files. 
     */ 
     
    #include <linux/module.h>  
    #include <linux/fs.h>  
    #include <linux/pagemap.h>  
    #include <linux/init.h>  
    #include <linux/string.h>  
    #include <linux/blkdev.h>  
    #include <linux/cramfs_fs.h>  
    #include <linux/slab.h>  
    #include <linux/cramfs_fs_sb.h>  
    #include <linux/buffer_head.h>  
    #include <linux/vfs.h>  
    #include <linux/mutex.h>  
     
    #include <asm/uaccess.h>   
      
    static const struct super_operations cramfs_ops;  
    static const struct inode_operations cramfs_dir_inode_operations;  
    static const struct file_operations cramfs_directory_operations;  
    static const struct address_space_operations cramfs_aops;  
      
    static DEFINE_MUTEX(read_mutex);  
      
      
    /* These two macros may change in future, to provide better st_ino 
       semantics. */ 
    #define CRAMINO(x)  (((x)->offset && (x)->size)?(x)->offset<<2:1)  
    #define OFFSET(x)   ((x)->i_ino)   
      
      
    static int cramfs_iget5_test(struct inode *inode, void *opaque)  
    {  
        struct cramfs_inode *cramfs_inode = opaque;  
        return inode->i_ino == CRAMINO(cramfs_inode) && inode->i_ino != 1;  
    }  
      
    static int cramfs_iget5_set(struct inode *inode, void *opaque)  
    {  
        struct cramfs_inode *cramfs_inode = opaque;  
        inode->i_ino = CRAMINO(cramfs_inode);  
        return 0;  
    }  
      
    static struct inode *get_cramfs_inode(struct super_block *sb,  
                    struct cramfs_inode * cramfs_inode)  
    {  
        struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),  
                            cramfs_iget5_test, cramfs_iget5_set,  
                            cramfs_inode);  
        static struct timespec zerotime;  
      
        if (inode && (inode->i_state & I_NEW)) {  
            inode->i_mode = cramfs_inode->mode;  
            inode->i_uid = cramfs_inode->uid;  
            inode->i_size = cramfs_inode->size;  
            inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;  
            inode->i_gid = cramfs_inode->gid;  
            /* Struct copy intentional */  
            inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;  
            /* inode->i_nlink is left 1 - arguably wrong for directories, 
               but it's the best we can do without reading the directory 
               contents.  1 yields the right result in GNU find, even 
               without -noleaf option. */  
            if (S_ISREG(inode->i_mode)) {  
                inode->i_fop = &generic_ro_fops;  
                inode->i_data.a_ops = &cramfs_aops;  
            } else if (S_ISDIR(inode->i_mode)) {  
                inode->i_op = &cramfs_dir_inode_operations;  
                inode->i_fop = &cramfs_directory_operations;  
            } else if (S_ISLNK(inode->i_mode)) {  
                inode->i_op = &page_symlink_inode_operations;  
                inode->i_data.a_ops = &cramfs_aops;  
            } else {  
                init_special_inode(inode, inode->i_mode,  
                    old_decode_dev(cramfs_inode->size));  
            }  
            unlock_new_inode(inode);  
        }  
        return inode;  
    }  
      
    static void cramfs_drop_inode(struct inode *inode)  
    {  
        if (inode->i_ino == 1)  
            generic_delete_inode(inode);  
        else  
            generic_drop_inode(inode);  
    }  
      
    /* 
     * We have our own block cache: don't fill up the buffer cache 
     * with the rom-image, because the way the filesystem is set 
     * up the accesses should be fairly regular and cached in the 
     * page cache and dentry tree anyway.. 
     * 
     * This also acts as a way to guarantee contiguous areas of up to 
     * BLKS_PER_BUF*PAGE_CACHE_SIZE, so that the caller doesn't need to 
     * worry about end-of-buffer issues even when decompressing a full 
     * page cache. 
     */ 
    #define READ_BUFFERS (2)   
    /* NEXT_BUFFER(): Loop over [0..(READ_BUFFERS-1)]. */ 
    #define NEXT_BUFFER(_ix) ((_ix) ^ 1)   
      
    /* 
     * BLKS_PER_BUF_SHIFT should be at least 2 to allow for "compressed" 
     * data that takes up more space than the original and with unlucky 
     * alignment. 
     */ 
    #define BLKS_PER_BUF_SHIFT  (2)  
    #define BLKS_PER_BUF        (1 << BLKS_PER_BUF_SHIFT)  
    #define BUFFER_SIZE     (BLKS_PER_BUF*PAGE_CACHE_SIZE)   
      
    static unsigned char read_buffers[READ_BUFFERS][BUFFER_SIZE];  
    static unsigned buffer_blocknr[READ_BUFFERS];  
    static struct super_block * buffer_dev[READ_BUFFERS];  
    static int next_buffer;  
      
    /* 
     * Returns a pointer to a buffer containing at least LEN bytes of 
     * filesystem starting at byte offset OFFSET into the filesystem. 
     */  
    static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)  
    {  
        struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;  
        struct page *pages[BLKS_PER_BUF];  
        unsigned i, blocknr, buffer;  
        unsigned long devsize;  
        char *data;  
      
        if (!len)  
            return NULL;  
        blocknr = offset >> PAGE_CACHE_SHIFT;  
        offset &= PAGE_CACHE_SIZE - 1;  
      
        /* Check if an existing buffer already has the data.. */  
        for (i = 0; i < READ_BUFFERS; i++) {  
            unsigned int blk_offset;  
      
            if (buffer_dev[i] != sb)  
                continue;  
            if (blocknr < buffer_blocknr[i])  
                continue;  
            blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;  
            blk_offset += offset;  
            if (blk_offset + len > BUFFER_SIZE)  
                continue;  
            return read_buffers[i] + blk_offset;  
        }  
      
        devsize = mapping->host->i_size >> PAGE_CACHE_SHIFT;  
      
        /* Ok, read in BLKS_PER_BUF pages completely first. */  
        for (i = 0; i < BLKS_PER_BUF; i++) {  
            struct page *page = NULL;  
      
            if (blocknr + i < devsize) {  
                page = read_mapping_page_async(mapping, blocknr + i,  
                                        NULL);  
                /* synchronous error? */  
                if (IS_ERR(page))  
                    page = NULL;  
            }  
            pages[i] = page;  
        }  
      
        for (i = 0; i < BLKS_PER_BUF; i++) {  
            struct page *page = pages[i];  
            if (page) {  
                wait_on_page_locked(page);  
                if (!PageUptodate(page)) {  
                    /* asynchronous error */  
                    page_cache_release(page);  
                    pages[i] = NULL;  
                }  
            }  
        }  
      
        buffer = next_buffer;  
        next_buffer = NEXT_BUFFER(buffer);  
        buffer_blocknr[buffer] = blocknr;  
        buffer_dev[buffer] = sb;  
      
        data = read_buffers[buffer];  
        for (i = 0; i < BLKS_PER_BUF; i++) {  
            struct page *page = pages[i];  
            if (page) {  
                memcpy(data, kmap(page), PAGE_CACHE_SIZE);  
                kunmap(page);  
                page_cache_release(page);  
            } else  
                memset(data, 0, PAGE_CACHE_SIZE);  
            data += PAGE_CACHE_SIZE;  
        }  
        return read_buffers[buffer] + offset;  
    }  
      
    static void cramfs_put_super(struct super_block *sb)  
    {  
        kfree(sb->s_fs_info);  
        sb->s_fs_info = NULL;  
    }  
      
    static int cramfs_remount(struct super_block *sb, int *flags, char *data)  
    {  
        *flags |= MS_RDONLY;  
        return 0;  
    }  
      
    static int cramfs_fill_super(struct super_block *sb, void *data, int silent)  
    {  
        int i;  
        struct cramfs_super super;  
        unsigned long root_offset;  
        struct cramfs_sb_info *sbi;  
        struct inode *root;  
      
        sb->s_flags |= MS_RDONLY;  
      
        sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);  
        if (!sbi)  
            return -ENOMEM;  
        sb->s_fs_info = sbi;  
      
        /* Invalidate the read buffers on mount: think disk change.. */  
        mutex_lock(&read_mutex);  
        for (i = 0; i < READ_BUFFERS; i++)  
            buffer_blocknr[i] = -1;  
      
        /* Read the first block and get the superblock from it */  
        memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));  
        mutex_unlock(&read_mutex);  
      
        /* Do sanity checks on the superblock */  
        if (super.magic != CRAMFS_MAGIC) {  
            /* check for wrong endianess */  
            if (super.magic == CRAMFS_MAGIC_WEND) {  
                if (!silent)  
                    printk(KERN_ERR "cramfs: wrong endianess\n");  
                goto out;  
            }  
      
            /* check at 512 byte offset */  
            mutex_lock(&read_mutex);  
            memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super));  
            mutex_unlock(&read_mutex);  
            if (super.magic != CRAMFS_MAGIC) {  
                if (super.magic == CRAMFS_MAGIC_WEND && !silent)  
                    printk(KERN_ERR "cramfs: wrong endianess\n");  
                else if (!silent)  
                    printk(KERN_ERR "cramfs: wrong magic\n");  
                goto out;  
            }  
        }  
      
        /* get feature flags first */  
        if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {  
            printk(KERN_ERR "cramfs: unsupported filesystem features\n");  
            goto out;  
        }  
      
        /* Check that the root inode is in a sane state */  
        if (!S_ISDIR(super.root.mode)) {  
            printk(KERN_ERR "cramfs: root is not a directory\n");  
            goto out;  
        }  
        root_offset = super.root.offset << 2;  
        if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {  
            sbi->size=super.size;  
            sbi->blocks=super.fsid.blocks;  
            sbi->files=super.fsid.files;  
        } else {  
            sbi->size=1<<28;  
            sbi->blocks=0;  
            sbi->files=0;  
        }  
        sbi->magic=super.magic;  
        sbi->flags=super.flags;  
        if (root_offset == 0)  
            printk(KERN_INFO "cramfs: empty filesystem");  
        else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&  
             ((root_offset != sizeof(struct cramfs_super)) &&  
              (root_offset != 512 + sizeof(struct cramfs_super))))  
        {  
            printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset);  
            goto out;  
        }  
      
        /* Set it all up.. */  
        sb->s_op = &cramfs_ops;  
        root = get_cramfs_inode(sb, &super.root);  
        if (!root)  
            goto out;  
        sb->s_root = d_alloc_root(root);  
        if (!sb->s_root) {  
            iput(root);  
            goto out;  
        }  
        return 0;  
    out:  
        kfree(sbi);  
        sb->s_fs_info = NULL;  
        return -EINVAL;  
    }  
      
    static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)  
    {  
        struct super_block *sb = dentry->d_sb;  
        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);  
      
        buf->f_type = CRAMFS_MAGIC;  
        buf->f_bsize = PAGE_CACHE_SIZE;  
        buf->f_blocks = CRAMFS_SB(sb)->blocks;  
        buf->f_bfree = 0;  
        buf->f_bavail = 0;  
        buf->f_files = CRAMFS_SB(sb)->files;  
        buf->f_ffree = 0;  
        buf->f_fsid.val[0] = (u32)id;  
        buf->f_fsid.val[1] = (u32)(id >> 32);  
        buf->f_namelen = CRAMFS_MAXPATHLEN;  
        return 0;  
    }  
      
    /* 
     * Read a cramfs directory entry. 
     */  
    static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)  
    {  
        struct inode *inode = filp->f_path.dentry->d_inode;  
        struct super_block *sb = inode->i_sb;  
        char *buf;  
        unsigned int offset;  
        int copied;  
      
        /* Offset within the thing. */  
        offset = filp->f_pos;  
        if (offset >= inode->i_size)  
            return 0;  
        /* Directory entries are always 4-byte aligned */  
        if (offset & 3)  
            return -EINVAL;  
      
        buf = kmalloc(CRAMFS_MAXPATHLEN, GFP_KERNEL);  
        if (!buf)  
            return -ENOMEM;  
      
        copied = 0;  
        while (offset < inode->i_size) {  
            struct cramfs_inode *de;  
            unsigned long nextoffset;  
            char *name;  
            ino_t ino;  
            mode_t mode;  
            int namelen, error;  
      
            mutex_lock(&read_mutex);  
            de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN);  
            name = (char *)(de+1);  
      
            /* 
             * Namelengths on disk are shifted by two 
             * and the name padded out to 4-byte boundaries 
             * with zeroes. 
             */  
            namelen = de->namelen << 2;  
            memcpy(buf, name, namelen);  
            ino = CRAMINO(de);  
            mode = de->mode;  
            mutex_unlock(&read_mutex);  
            nextoffset = offset + sizeof(*de) + namelen;  
            for (;;) {  
                if (!namelen) {  
                    kfree(buf);  
                    return -EIO;  
                }  
                if (buf[namelen-1])  
                    break;  
                namelen--;  
            }  
            error = filldir(dirent, buf, namelen, offset, ino, mode >> 12);  
            if (error)  
                break;  
      
            offset = nextoffset;  
            filp->f_pos = offset;  
            copied++;  
        }  
        kfree(buf);  
        return 0;  
    }  
      
    /* 
     * Lookup and fill in the inode data.. 
     */  
    static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)  
    {  
        unsigned int offset = 0;  
        int sorted;  
      
        mutex_lock(&read_mutex);  
        sorted = CRAMFS_SB(dir->i_sb)->flags & CRAMFS_FLAG_SORTED_DIRS;  
        while (offset < dir->i_size) {  
            struct cramfs_inode *de;  
            char *name;  
            int namelen, retval;  
      
            de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN);  
            name = (char *)(de+1);  
      
            /* Try to take advantage of sorted directories */  
            if (sorted && (dentry->d_name.name[0] < name[0]))  
                break;  
      
            namelen = de->namelen << 2;  
            offset += sizeof(*de) + namelen;  
      
            /* Quick check that the name is roughly the right length */  
            if (((dentry->d_name.len + 3) & ~3) != namelen)  
                continue;  
      
            for (;;) {  
                if (!namelen) {  
                    mutex_unlock(&read_mutex);  
                    return ERR_PTR(-EIO);  
                }  
                if (name[namelen-1])  
                    break;  
                namelen--;  
            }  
            if (namelen != dentry->d_name.len)  
                continue;  
            retval = memcmp(dentry->d_name.name, name, namelen);  
            if (retval > 0)  
                continue;  
            if (!retval) {  
                struct cramfs_inode entry = *de;  
                mutex_unlock(&read_mutex);  
                d_add(dentry, get_cramfs_inode(dir->i_sb, &entry));  
                return NULL;  
            }  
            /* else (retval < 0) */  
            if (sorted)  
                break;  
        }  
        mutex_unlock(&read_mutex);  
        d_add(dentry, NULL);  
        return NULL;  
    }  
      
    static int cramfs_readpage(struct file *file, struct page * page)  
    {  
        struct inode *inode = page->mapping->host;  
        u32 maxblock;  
        int bytes_filled;  
        void *pgdata;  
      
        maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;  
        bytes_filled = 0;  
        pgdata = kmap(page);  
      
        if (page->index < maxblock) {  
            struct super_block *sb = inode->i_sb;  
            u32 blkptr_offset = OFFSET(inode) + page->index*4;  
            u32 start_offset, compr_len;  
      
            start_offset = OFFSET(inode) + maxblock*4;  
            mutex_lock(&read_mutex);  
            if (page->index)  
                start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4,  
                    4);  
            compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) -  
                start_offset);  
            mutex_unlock(&read_mutex);  
      
            if (compr_len == 0)  
                ; /* hole */  
            else if (unlikely(compr_len > (PAGE_CACHE_SIZE << 1))) {  
                pr_err("cramfs: bad compressed blocksize %u\n",  
                    compr_len);  
                goto err;  
            } else {  
                mutex_lock(&read_mutex);  
                bytes_filled = cramfs_uncompress_block(pgdata,  
                     PAGE_CACHE_SIZE,  
                     cramfs_read(sb, start_offset, compr_len),  
                     compr_len);  
                mutex_unlock(&read_mutex);  
                if (unlikely(bytes_filled < 0))  
                    goto err;  
            }  
        }  
      
        memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);  
        flush_dcache_page(page);  
        kunmap(page);  
        SetPageUptodate(page);  
        unlock_page(page);  
        return 0;  
      
    err:  
        kunmap(page);  
        ClearPageUptodate(page);  
        SetPageError(page);  
        unlock_page(page);  
        return 0;  
    }  
      
    static const struct address_space_operations cramfs_aops = {  
        .readpage = cramfs_readpage  
    };  
      
    /* 
     * Our operations: 
     */  
      
    /* 
     * A directory can only readdir 
     */  
    static const struct file_operations cramfs_directory_operations = {  
        .llseek     = generic_file_llseek,  
        .read       = generic_read_dir,  
        .readdir    = cramfs_readdir,  
    };  
      
    static const struct inode_operations cramfs_dir_inode_operations = {  
        .lookup     = cramfs_lookup,  
    };  
      
    static const struct super_operations cramfs_ops = {  
        .put_super  = cramfs_put_super,  
        .remount_fs = cramfs_remount,  
        .statfs     = cramfs_statfs,  
        .drop_inode = cramfs_drop_inode,  
    };  
      
    static int cramfs_get_sb(struct file_system_type *fs_type,  
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)  
    {  
        return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super,  
                   mnt);  
    }  
      
    static struct file_system_type cramfs_fs_type = {  
        .owner      = THIS_MODULE,  
        .name       = "cramfs",  
        .get_sb     = cramfs_get_sb,  
        .kill_sb    = kill_block_super,  
        .fs_flags   = FS_REQUIRES_DEV,  
    };  
      
    static int __init init_cramfs_fs(void)  
    {  
        int rv;  
      
        rv = cramfs_uncompress_init();  
        if (rv < 0)  
            return rv;  
        rv = register_filesystem(&cramfs_fs_type);  
        if (rv < 0)  
            cramfs_uncompress_exit();  
        return rv;  
    }  
      
    static void __exit exit_cramfs_fs(void)  
    {  
        cramfs_uncompress_exit();  
        unregister_filesystem(&cramfs_fs_type);  
    }  
      
    module_init(init_cramfs_fs)  
    module_exit(exit_cramfs_fs)  
    MODULE_LICENSE("GPL");  
    


    修改后的程序

    /* 
     * Compressed rom filesystem for Linux. 
     * 
     * Copyright (C) 1999 Linus Torvalds. 
     * 
     * This file is released under the GPL. 
     */  
      
    /* 
     * These are the VFS interfaces to the compressed rom filesystem. 
     * The actual compression is based on zlib, see the other files. 
     */ 
     
    #include <linux/module.h>  
    #include <linux/fs.h>  
    #include <linux/pagemap.h>  
    #include <linux/init.h>  
    #include <linux/string.h>  
    #include <linux/blkdev.h>  
    #include <linux/cramfs_fs.h>  
    #include <linux/slab.h>  
    #include <linux/cramfs_fs_sb.h>  
    #include <linux/buffer_head.h>  
    #include <linux/vfs.h>  
    #include <linux/mutex.h>  
     
    #include <asm/uaccess.h>  
    #include <linux/mtd/mtd.h>   
    #include <mtd/mtd-abi.h>    
      
    static const struct super_operations cramfs_ops;  
    static const struct inode_operations cramfs_dir_inode_operations;  
    static const struct file_operations cramfs_directory_operations;  
    static const struct address_space_operations cramfs_aops;  
      
    static DEFINE_MUTEX(read_mutex);  
      
      
    /* These two macros may change in future, to provide better st_ino 
       semantics. */ 
    #define CRAMINO(x)  (((x)->offset && (x)->size)?(x)->offset<<2:1)  
    #define OFFSET(x)   ((x)->i_ino)   
      
      
    static int cramfs_iget5_test(struct inode *inode, void *opaque)  
    {  
        struct cramfs_inode *cramfs_inode = opaque;  
        return inode->i_ino == CRAMINO(cramfs_inode) && inode->i_ino != 1;  
    }  
      
    static int cramfs_iget5_set(struct inode *inode, void *opaque)  
    {  
        struct cramfs_inode *cramfs_inode = opaque;  
        inode->i_ino = CRAMINO(cramfs_inode);  
        return 0;  
    }  
      
    static struct inode *get_cramfs_inode(struct super_block *sb,  
                    struct cramfs_inode * cramfs_inode)  
    {  
        struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),  
                            cramfs_iget5_test, cramfs_iget5_set,  
                            cramfs_inode);  
        static struct timespec zerotime;  
      
        if (inode && (inode->i_state & I_NEW)) {  
            inode->i_mode = cramfs_inode->mode;  
            inode->i_uid = cramfs_inode->uid;  
            inode->i_size = cramfs_inode->size;  
            inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;  
            inode->i_gid = cramfs_inode->gid;  
            /* Struct copy intentional */  
            inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;  
            /* inode->i_nlink is left 1 - arguably wrong for directories, 
               but it's the best we can do without reading the directory 
               contents.  1 yields the right result in GNU find, even 
               without -noleaf option. */  
            if (S_ISREG(inode->i_mode)) {  
                inode->i_fop = &generic_ro_fops;  
                inode->i_data.a_ops = &cramfs_aops;  
            } else if (S_ISDIR(inode->i_mode)) {  
                inode->i_op = &cramfs_dir_inode_operations;  
                inode->i_fop = &cramfs_directory_operations;  
            } else if (S_ISLNK(inode->i_mode)) {  
                inode->i_op = &page_symlink_inode_operations;  
                inode->i_data.a_ops = &cramfs_aops;  
            } else {  
                init_special_inode(inode, inode->i_mode,  
                    old_decode_dev(cramfs_inode->size));  
            }  
            unlock_new_inode(inode);  
        }  
        return inode;  
    }  
      
    static void cramfs_drop_inode(struct inode *inode)  
    {  
        if (inode->i_ino == 1)  
            generic_delete_inode(inode);  
        else  
            generic_drop_inode(inode);  
    }  
      
    /* 
     * We have our own block cache: don't fill up the buffer cache 
     * with the rom-image, because the way the filesystem is set 
     * up the accesses should be fairly regular and cached in the 
     * page cache and dentry tree anyway.. 
     * 
     * This also acts as a way to guarantee contiguous areas of up to 
     * BLKS_PER_BUF*PAGE_CACHE_SIZE, so that the caller doesn't need to 
     * worry about end-of-buffer issues even when decompressing a full 
     * page cache. 
     */ 
    #define READ_BUFFERS (2)   
    /* NEXT_BUFFER(): Loop over [0..(READ_BUFFERS-1)]. */ 
    #define NEXT_BUFFER(_ix) ((_ix) ^ 1)   
      
    /* 
     * BLKS_PER_BUF_SHIFT should be at least 2 to allow for "compressed" 
     * data that takes up more space than the original and with unlucky 
     * alignment. 
     */ 
    #define BLKS_PER_BUF_SHIFT  (2)  
    #define BLKS_PER_BUF        (1 << BLKS_PER_BUF_SHIFT)  
    #define BUFFER_SIZE     (BLKS_PER_BUF*PAGE_CACHE_SIZE)   
      
    static unsigned char read_buffers[READ_BUFFERS][BUFFER_SIZE];  
    static unsigned buffer_blocknr[READ_BUFFERS];  
    static struct super_block * buffer_dev[READ_BUFFERS];  
    static int next_buffer;  
      
    //mike change to support bad block: cramfs_read-> cramfs_read_old   
    /* 
     * Returns a pointer to a buffer containing at least LEN bytes of 
     * filesystem starting at byte offset OFFSET into the filesystem. 
     */  
    static void *cramfs_read_old(struct super_block *sb, unsigned int offset, unsigned int len)  
    {  
        struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;  
        struct page *pages[BLKS_PER_BUF];  
        unsigned i, blocknr, buffer;  
        unsigned long devsize;  
        char *data;  
      
        if (!len)  
            return NULL;  
        blocknr = offset >> PAGE_CACHE_SHIFT;  
        offset &= PAGE_CACHE_SIZE - 1;  
      
        /* Check if an existing buffer already has the data.. */  
        for (i = 0; i < READ_BUFFERS; i++) {  
            unsigned int blk_offset;  
      
            if (buffer_dev[i] != sb)  
                continue;  
            if (blocknr < buffer_blocknr[i])  
                continue;  
            blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;  
            blk_offset += offset;  
            if (blk_offset + len > BUFFER_SIZE)  
                continue;  
            return read_buffers[i] + blk_offset;  
        }  
      
        devsize = mapping->host->i_size >> PAGE_CACHE_SHIFT;  
      
        /* Ok, read in BLKS_PER_BUF pages completely first. */  
        for (i = 0; i < BLKS_PER_BUF; i++) {  
            struct page *page = NULL;  
      
            if (blocknr + i < devsize) {  
                page = read_mapping_page_async(mapping, blocknr + i,  
                                        NULL);  
                /* synchronous error? */  
                if (IS_ERR(page))  
                    page = NULL;  
            }  
            pages[i] = page;  
        }  
      
        for (i = 0; i < BLKS_PER_BUF; i++) {  
            struct page *page = pages[i];  
            if (page) {  
                wait_on_page_locked(page);  
                if (!PageUptodate(page)) {  
                    /* asynchronous error */  
                    page_cache_release(page);  
                    pages[i] = NULL;  
                }  
            }  
        }  
      
        buffer = next_buffer;  
        next_buffer = NEXT_BUFFER(buffer);  
        buffer_blocknr[buffer] = blocknr;  
        buffer_dev[buffer] = sb;  
      
        data = read_buffers[buffer];  
        for (i = 0; i < BLKS_PER_BUF; i++) {  
            struct page *page = pages[i];  
            if (page) {  
                memcpy(data, kmap(page), PAGE_CACHE_SIZE);  
                kunmap(page);  
                page_cache_release(page);  
            } else  
                memset(data, 0, PAGE_CACHE_SIZE);  
            data += PAGE_CACHE_SIZE;  
        }  
        return read_buffers[buffer] + offset;  
    }  
      
    //mike added to support bad block   
    static int get_block_map(struct super_block *sb, int block)   
    {   
        struct cramfs_sb_info *sbi = sb->s_fs_info;   
        struct mtd_info *mtd = sbi->mtd;   
        int *block_map = (int*)sbi->block_map;   
        int blocks = sbi->nblock;   
        int pblock = -1;   
        int i;   
        if(block_map[block]==-1) {   
            for(i=0; i<blocks; i++) {   
                if(block_map[i] == -1) {   
                    break;   
                }   
                pblock = block_map[i];   
            }   
            pblock++;   
            while(i<=block+4 && i<blocks) {   
                while(mtd->block_isbad(mtd, pblock*mtd->erasesize)) {   
                    printk("cramfs: skip bad block %d(page %d)\n", pblock, pblock*32+4096);   
                    pblock++;   
                }   
                block_map[i] = pblock;   
                i++;   
                pblock++;   
            }   
        }   
        return block_map[block];   
    }   
    static void *cramfs_read_nand(struct super_block *sb, unsigned int offset, unsigned int len)   
    {   
        unsigned i, blocknr, buffer;   
        char *data;   
        struct cramfs_sb_info *sbi = sb->s_fs_info;   
        struct mtd_info *mtd = sbi->mtd;   
        unsigned mblock, moffset, pblock, maddr;   
        int retv;   
        size_t dummy;   
        if (!len)   
            return NULL;   
        blocknr = offset >> PAGE_CACHE_SHIFT;   
        for (i = 0; i < READ_BUFFERS; i++) {   
            unsigned int blk_offset;   
            if (buffer_dev[i] != sb)   
                continue;   
            if (blocknr < buffer_blocknr[i])   
                continue;   
            blk_offset = (blocknr - buffer_blocknr[i]) << PAGE_CACHE_SHIFT;   
            blk_offset += (offset & (PAGE_CACHE_SIZE-1));   
            if (blk_offset + len > BUFFER_SIZE)   
                continue;   
            return read_buffers[i] + blk_offset;   
        }   
        buffer = next_buffer;   
        next_buffer = NEXT_BUFFER(buffer);   
        buffer_blocknr[buffer] = blocknr;   
        buffer_dev[buffer] = sb;   
        mblock = offset/mtd->erasesize;   
        moffset = (offset & (mtd->erasesize-1))&(~(PAGE_CACHE_SIZE-1));   
        offset &= (PAGE_CACHE_SIZE-1);   
        pblock = get_block_map(sb, mblock);   
        maddr = pblock*mtd->erasesize + moffset;   
        data = read_buffers[buffer];   
        if( moffset+BUFFER_SIZE <= mtd->erasesize ){   
            retv = mtd->read(mtd, maddr, BUFFER_SIZE, &dummy, data);   
        }else{   
            int read_size;   
            read_size = mtd->erasesize-moffset;   
            retv = mtd->read(mtd, maddr, read_size, &dummy, data);   
            pblock = get_block_map(sb, mblock+1);   
            maddr = pblock*mtd->erasesize;   
            retv = mtd->read(mtd, maddr, (BUFFER_SIZE-read_size), &dummy, data+read_size);   
        }   
        return read_buffers[buffer] + offset;   
    }   
    static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len)   
    {   
        struct cramfs_sb_info *sbi = sb->s_fs_info;   
        if(sbi->nand){   
            return cramfs_read_nand(sb, offset, len);   
        }else{   
            return cramfs_read_old(sb, offset, len);   
        }   
    }   
    //mike added end   
    static void cramfs_put_super(struct super_block *sb)  
    {  
        kfree(sb->s_fs_info);  
        sb->s_fs_info = NULL;  
    }  
      
    static int cramfs_remount(struct super_block *sb, int *flags, char *data)  
    {  
        *flags |= MS_RDONLY;  
        return 0;  
    }  
      
    static int cramfs_fill_super(struct super_block *sb, void *data, int silent)  
    {  
        int i;  
        struct cramfs_super super;  
        unsigned long root_offset;  
        struct cramfs_sb_info *sbi;  
        struct inode *root;  
      
        sb->s_flags |= MS_RDONLY;  
      
        sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);  
        if (!sbi)  
            return -ENOMEM;  
        sb->s_fs_info = sbi;  
      
        /* Invalidate the read buffers on mount: think disk change.. */  
        mutex_lock(&read_mutex);  
        for (i = 0; i < READ_BUFFERS; i++)  
            buffer_blocknr[i] = -1;  
    //mike added to support bad block   
        sbi->nand = 0;   
        if(MAJOR(sb->s_dev) == MTD_BLOCK_MAJOR)  
        {   
            struct mtd_info *mtd;   
            int *block_map;  
            u_int32_t num,  blocks;  
            mtd = get_mtd_device(NULL, MINOR(sb->s_dev));   
      
            if(!mtd)  
                goto not_mtdblock;   
                  
            if(mtd->type != MTD_NANDFLASH)   
                goto not_mtdblock;   
      
            sbi->mtd = mtd;   
            sbi->nand = 1;   
      
            blocks = (long)(mtd->size) / (long)(mtd->erasesize);   
            block_map = (int*)kmalloc(blocks*sizeof(int), GFP_KERNEL);   
      
            if(block_map == NULL)  
                goto not_mtdblock;  
              
              
            for(num=0; num<blocks; num++)  
            {  
                block_map[num] = -1;   
            }  
              
            sbi->block_map = block_map;   
            sbi->nblock = blocks;   
      
        }  
          
    not_mtdblock:   
    //mike added end   
        /* Read the first block and get the superblock from it */  
        memcpy(&super, cramfs_read(sb, 0, sizeof(super)), sizeof(super));  
        mutex_unlock(&read_mutex);  
      
        /* Do sanity checks on the superblock */  
        if (super.magic != CRAMFS_MAGIC) {  
            /* check for wrong endianess */  
            if (super.magic == CRAMFS_MAGIC_WEND) {  
                if (!silent)  
                    printk(KERN_ERR "cramfs: wrong endianess\n");  
                goto out;  
            }  
      
            /* check at 512 byte offset */  
            mutex_lock(&read_mutex);  
            memcpy(&super, cramfs_read(sb, 512, sizeof(super)), sizeof(super));  
            mutex_unlock(&read_mutex);  
            if (super.magic != CRAMFS_MAGIC) {  
                if (super.magic == CRAMFS_MAGIC_WEND && !silent)  
                    printk(KERN_ERR "cramfs: wrong endianess\n");  
                else if (!silent)  
                    printk(KERN_ERR "cramfs: wrong magic\n");  
                goto out;  
            }  
        }  
      
        /* get feature flags first */  
        if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {  
            printk(KERN_ERR "cramfs: unsupported filesystem features\n");  
            goto out;  
        }  
      
        /* Check that the root inode is in a sane state */  
        if (!S_ISDIR(super.root.mode)) {  
            printk(KERN_ERR "cramfs: root is not a directory\n");  
            goto out;  
        }  
        root_offset = super.root.offset << 2;  
        if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) {  
            sbi->size=super.size;  
            sbi->blocks=super.fsid.blocks;  
            sbi->files=super.fsid.files;  
        } else {  
            sbi->size=1<<28;  
            sbi->blocks=0;  
            sbi->files=0;  
        }  
        sbi->magic=super.magic;  
        sbi->flags=super.flags;  
        if (root_offset == 0)  
            printk(KERN_INFO "cramfs: empty filesystem");  
        else if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) &&  
             ((root_offset != sizeof(struct cramfs_super)) &&  
              (root_offset != 512 + sizeof(struct cramfs_super))))  
        {  
            printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset);  
            goto out;  
        }  
      
        /* Set it all up.. */  
        sb->s_op = &cramfs_ops;  
        root = get_cramfs_inode(sb, &super.root);  
        if (!root)  
            goto out;  
        sb->s_root = d_alloc_root(root);  
        if (!sb->s_root) {  
            iput(root);  
            goto out;  
        }  
        return 0;  
    out:  
        kfree(sbi);  
        sb->s_fs_info = NULL;  
        return -EINVAL;  
    }  
      
    static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)  
    {  
        struct super_block *sb = dentry->d_sb;  
        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);  
      
        buf->f_type = CRAMFS_MAGIC;  
        buf->f_bsize = PAGE_CACHE_SIZE;  
        buf->f_blocks = CRAMFS_SB(sb)->blocks;  
        buf->f_bfree = 0;  
        buf->f_bavail = 0;  
        buf->f_files = CRAMFS_SB(sb)->files;  
        buf->f_ffree = 0;  
        buf->f_fsid.val[0] = (u32)id;  
        buf->f_fsid.val[1] = (u32)(id >> 32);  
        buf->f_namelen = CRAMFS_MAXPATHLEN;  
        return 0;  
    }  
      
    /* 
     * Read a cramfs directory entry. 
     */  
    static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)  
    {  
        struct inode *inode = filp->f_path.dentry->d_inode;  
        struct super_block *sb = inode->i_sb;  
        char *buf;  
        unsigned int offset;  
        int copied;  
      
        /* Offset within the thing. */  
        offset = filp->f_pos;  
        if (offset >= inode->i_size)  
            return 0;  
        /* Directory entries are always 4-byte aligned */  
        if (offset & 3)  
            return -EINVAL;  
      
        buf = kmalloc(CRAMFS_MAXPATHLEN, GFP_KERNEL);  
        if (!buf)  
            return -ENOMEM;  
      
        copied = 0;  
        while (offset < inode->i_size) {  
            struct cramfs_inode *de;  
            unsigned long nextoffset;  
            char *name;  
            ino_t ino;  
            mode_t mode;  
            int namelen, error;  
      
            mutex_lock(&read_mutex);  
            de = cramfs_read(sb, OFFSET(inode) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN);  
            name = (char *)(de+1);  
      
            /* 
             * Namelengths on disk are shifted by two 
             * and the name padded out to 4-byte boundaries 
             * with zeroes. 
             */  
            namelen = de->namelen << 2;  
            memcpy(buf, name, namelen);  
            ino = CRAMINO(de);  
            mode = de->mode;  
            mutex_unlock(&read_mutex);  
            nextoffset = offset + sizeof(*de) + namelen;  
            for (;;) {  
                if (!namelen) {  
                    kfree(buf);  
                    return -EIO;  
                }  
                if (buf[namelen-1])  
                    break;  
                namelen--;  
            }  
            error = filldir(dirent, buf, namelen, offset, ino, mode >> 12);  
            if (error)  
                break;  
      
            offset = nextoffset;  
            filp->f_pos = offset;  
            copied++;  
        }  
        kfree(buf);  
        return 0;  
    }  
      
    /* 
     * Lookup and fill in the inode data.. 
     */  
    static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)  
    {  
        unsigned int offset = 0;  
        int sorted;  
      
        mutex_lock(&read_mutex);  
        sorted = CRAMFS_SB(dir->i_sb)->flags & CRAMFS_FLAG_SORTED_DIRS;  
        while (offset < dir->i_size) {  
            struct cramfs_inode *de;  
            char *name;  
            int namelen, retval;  
      
            de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN);  
            name = (char *)(de+1);  
      
            /* Try to take advantage of sorted directories */  
            if (sorted && (dentry->d_name.name[0] < name[0]))  
                break;  
      
            namelen = de->namelen << 2;  
            offset += sizeof(*de) + namelen;  
      
            /* Quick check that the name is roughly the right length */  
            if (((dentry->d_name.len + 3) & ~3) != namelen)  
                continue;  
      
            for (;;) {  
                if (!namelen) {  
                    mutex_unlock(&read_mutex);  
                    return ERR_PTR(-EIO);  
                }  
                if (name[namelen-1])  
                    break;  
                namelen--;  
            }  
            if (namelen != dentry->d_name.len)  
                continue;  
            retval = memcmp(dentry->d_name.name, name, namelen);  
            if (retval > 0)  
                continue;  
            if (!retval) {  
                struct cramfs_inode entry = *de;  
                mutex_unlock(&read_mutex);  
                d_add(dentry, get_cramfs_inode(dir->i_sb, &entry));  
                return NULL;  
            }  
            /* else (retval < 0) */  
            if (sorted)  
                break;  
        }  
        mutex_unlock(&read_mutex);  
        d_add(dentry, NULL);  
        return NULL;  
    }  
      
    static int cramfs_readpage(struct file *file, struct page * page)  
    {  
        struct inode *inode = page->mapping->host;  
        u32 maxblock;  
        int bytes_filled;  
        void *pgdata;  
      
        maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;  
        bytes_filled = 0;  
        pgdata = kmap(page);  
      
        if (page->index < maxblock) {  
            struct super_block *sb = inode->i_sb;  
            u32 blkptr_offset = OFFSET(inode) + page->index*4;  
            u32 start_offset, compr_len;  
      
            start_offset = OFFSET(inode) + maxblock*4;  
            mutex_lock(&read_mutex);  
            if (page->index)  
                start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4,  
                    4);  
            compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) -  
                start_offset);  
            mutex_unlock(&read_mutex);  
      
            if (compr_len == 0)  
                ; /* hole */  
            else if (unlikely(compr_len > (PAGE_CACHE_SIZE << 1))) {  
                pr_err("cramfs: bad compressed blocksize %u\n",  
                    compr_len);  
                goto err;  
            } else {  
                mutex_lock(&read_mutex);  
                bytes_filled = cramfs_uncompress_block(pgdata,  
                     PAGE_CACHE_SIZE,  
                     cramfs_read(sb, start_offset, compr_len),  
                     compr_len);  
                mutex_unlock(&read_mutex);  
                if (unlikely(bytes_filled < 0))  
                    goto err;  
            }  
        }  
      
        memset(pgdata + bytes_filled, 0, PAGE_CACHE_SIZE - bytes_filled);  
        flush_dcache_page(page);  
        kunmap(page);  
        SetPageUptodate(page);  
        unlock_page(page);  
        return 0;  
      
    err:  
        kunmap(page);  
        ClearPageUptodate(page);  
        SetPageError(page);  
        unlock_page(page);  
        return 0;  
    }  
      
    static const struct address_space_operations cramfs_aops = {  
        .readpage = cramfs_readpage  
    };  
      
    /* 
     * Our operations: 
     */  
      
    /* 
     * A directory can only readdir 
     */  
    static const struct file_operations cramfs_directory_operations = {  
        .llseek     = generic_file_llseek,  
        .read       = generic_read_dir,  
        .readdir    = cramfs_readdir,  
    };  
      
    static const struct inode_operations cramfs_dir_inode_operations = {  
        .lookup     = cramfs_lookup,  
    };  
      
    static const struct super_operations cramfs_ops = {  
        .put_super  = cramfs_put_super,  
        .remount_fs = cramfs_remount,  
        .statfs     = cramfs_statfs,  
        .drop_inode = cramfs_drop_inode,  
    };  
      
    static int cramfs_get_sb(struct file_system_type *fs_type,  
        int flags, const char *dev_name, void *data, struct vfsmount *mnt)  
    {  
        return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super,  
                   mnt);  
    }  
      
    static struct file_system_type cramfs_fs_type = {  
        .owner      = THIS_MODULE,  
        .name       = "cramfs",  
        .get_sb     = cramfs_get_sb,  
        .kill_sb    = kill_block_super,  
        .fs_flags   = FS_REQUIRES_DEV,  
    };  
      
    static int __init init_cramfs_fs(void)  
    {  
        int rv;  
      
        rv = cramfs_uncompress_init();  
        if (rv < 0)  
            return rv;  
        rv = register_filesystem(&cramfs_fs_type);  
        if (rv < 0)  
            cramfs_uncompress_exit();  
        return rv;  
    }  
      
    static void __exit exit_cramfs_fs(void)  
    {  
        cramfs_uncompress_exit();  
        unregister_filesystem(&cramfs_fs_type);  
    }  
      
    module_init(init_cramfs_fs)  
    module_exit(exit_cramfs_fs)  
    MODULE_LICENSE("GPL");  
    



     

    你可能感兴趣的:(cache,struct,File,null,buffer,patch)