lkml.org 
[lkml]   [2010]   [Mar]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patches in this message
    /
    From
    SubjectRe: RFC: direct MTD support for SquashFS
    Date
    Now with the patch series, sorry.

    Ferenc Wagner <wferi@niif.hu> writes:

    > I've got one more patch, which I forgot to export, to pull out the
    > common logic from the backend init functions back into squashfs_read_data().
    > With the bdev backend, that entails reading the first block twice in a
    > row most of the time. This again could be worked around by extending
    > the backend interface, but I'm not sure if it's worth it.

    Here it is. I also corrected the name of SQUASHFS_METADATA_SIZE, so it
    may as well compile now.
    --
    Regards,
    Feri.

    From 1318e378d15008c89971f4c300738bd46d0fd2ba Mon Sep 17 00:00:00 2001
    From: Ferenc Wagner <wferi@niif.hu>
    Date: Thu, 18 Mar 2010 03:12:01 +0100
    Subject: [PATCH] squashfs: add backend plugin framework

    ---
    fs/squashfs/Makefile | 3 +-
    fs/squashfs/backend.c | 24 +++++++++
    fs/squashfs/backend.h | 22 ++++++++
    fs/squashfs/bdev.c | 110 ++++++++++++++++++++++++++++++++++++++++++
    fs/squashfs/squashfs.h | 9 +++-
    fs/squashfs/squashfs_fs_sb.h | 2 +
    6 files changed, 168 insertions(+), 2 deletions(-)
    create mode 100644 fs/squashfs/backend.c
    create mode 100644 fs/squashfs/backend.h
    create mode 100644 fs/squashfs/bdev.c

    diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
    index 45aaefd..0f02891 100644
    --- a/fs/squashfs/Makefile
    +++ b/fs/squashfs/Makefile
    @@ -4,5 +4,6 @@

    obj-$(CONFIG_SQUASHFS) += squashfs.o
    squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
    -squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
    +squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o backend.o
    squashfs-$(CONFIG_SQUASHFS_LZMA) += lzma_wrapper.o
    +squashfs-$(CONFIG_BLOCK) += bdev.o
    diff --git a/fs/squashfs/backend.c b/fs/squashfs/backend.c
    new file mode 100644
    index 0000000..4411c60
    --- /dev/null
    +++ b/fs/squashfs/backend.c
    @@ -0,0 +1,24 @@
    +#include <linux/fs.h>
    +
    +#include "squashfs_fs_i.h"
    +#include "squashfs.h"
    +#include "backend.h"
    +
    +const struct squashfs_backend *backends[] = {
    +#ifdef CONFIG_BLOCK
    + &squashfs_bdev_ops,
    +#endif
    + NULL
    +};
    +
    +const struct squashfs_backend *
    +squashfs_find_backend(struct file_system_type *fs_type, int flags,
    + const char *dev_name, void *data, struct vfsmount *mnt)
    +{
    + const struct squashfs_backend **b;
    +
    + for (b = backends; *b; b++)
    + if (!(*b)->probe(fs_type, flags, dev_name, data, mnt))
    + break;
    + return *b;
    +}
    diff --git a/fs/squashfs/backend.h b/fs/squashfs/backend.h
    new file mode 100644
    index 0000000..ca3ffe1
    --- /dev/null
    +++ b/fs/squashfs/backend.h
    @@ -0,0 +1,22 @@
    +#include <linux/fs.h>
    +#include <linux/vfs.h>
    +
    +#include "squashfs_fs_sb.h"
    +
    +struct squashfs_backend {
    + void *(*init)(struct squashfs_sb_info *, u64, size_t);
    + void (*free)(struct squashfs_sb_info *);
    + ssize_t (*read)(struct squashfs_sb_info *, void **, size_t);
    + int (*probe)(struct file_system_type *, int, const char *,
    + void*, struct vfsmount *);
    + void (*kill)(struct squashfs_sb_info *);
    + loff_t (*size)(const struct super_block *);
    + const char *(*devname)(const struct super_block *, char *);
    +};
    +
    +/* Dummy, until the original is nuked */
    +static inline int squashfs_fill_super2(struct super_block *sb, void *data,
    + int silent, int (*add_bend)(struct super_block *))
    +{
    + return -1;
    +}
    diff --git a/fs/squashfs/bdev.c b/fs/squashfs/bdev.c
    new file mode 100644
    index 0000000..c1d4389
    --- /dev/null
    +++ b/fs/squashfs/bdev.c
    @@ -0,0 +1,110 @@
    +#include <linux/fs.h>
    +#include <linux/buffer_head.h>
    +
    +#include "squashfs_fs_i.h"
    +#include "squashfs.h"
    +#include "backend.h"
    +
    +struct squashfs_bdev {
    + int devblksize; /* FIXME: == s->s_blocksize(_bits)? */
    + unsigned short devblksize_log2;
    + size_t bytes_left;
    + struct buffer_head **bh;
    + int bh_index; /* number of consumed buffer_heads */
    + int offset; /* offset of next byte in buffer_head */
    +};
    +
    +/* A backend is initialized for each SquashFS block read operation,
    + * making further sequential reads possible from the block.
    + */
    +static void *bdev_init(struct squashfs_sb_info *msblk, u64 index, size_t length)
    +{
    + struct squashfs_bdev *bdev = msblk->backend_data;
    + struct buffer_head *bh;
    +
    + bh = kcalloc((max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE)
    + >> bdev->devblksize_log2) + 1,
    + sizeof(*bh), GFP_KERNEL);
    + if (!bh)
    + goto nomem;
    +
    + /* different preread for data blocks and metadata blocks */
    +
    + bdev->bh_index = 0;
    + bdev->bytes_left = length;
    + return bdev;
    +
    +nomem:
    + ERROR("failed to allocate buffer_heads\n");
    + return NULL;
    +}
    +
    +static void bdev_free(struct squashfs_sb_info *msblk)
    +{
    + struct squashfs_bdev *bdev = msblk->backend_data;
    + kfree(bdev->bh);
    + bdev->bh = 0; /* FIXME: to make bdev_kill universal (see there) */
    +}
    +
    +static ssize_t bdev_read(struct squashfs_sb_info *msblk, void **buf, size_t len)
    +{
    + return -ENOSYS;
    +}
    +
    +static int add_bdev_backend(struct super_block *sb)
    +{
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    + struct squashfs_bdev *bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
    +
    + if (!bdev)
    + return -ENOMEM;
    +
    + bdev->devblksize = sb_min_blocksize(sb, BLOCK_SIZE);
    + bdev->devblksize_log2 = ffz(~bdev->devblksize);
    +
    + msblk->backend = &squashfs_bdev_ops;
    + msblk->backend_data = bdev;
    + return 0;
    +}
    +
    +static int fill_bdev_super(struct super_block *sb, void *data, int silent)
    +{
    + return squashfs_fill_super2(sb, data, silent, add_bdev_backend);
    +}
    +
    +static int bdev_probe(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,
    + fill_bdev_super, mnt);
    +}
    +
    +static void bdev_kill(struct squashfs_sb_info *msblk)
    +{
    + struct squashfs_bdev *bdev = msblk->backend_data;
    + if (bdev) {
    + kfree(bdev->bh); /* FIXME: can this be nonzero? cf. bdev_free */
    + kfree(bdev);
    + }
    +}
    +
    +static loff_t bdev_size(const struct super_block *sb)
    +{
    + return i_size_read(sb->s_bdev->bd_inode);
    +}
    +
    +static const char *bdev_devname(const struct super_block *sb, char *buffer)
    +{
    + return bdevname(sb->s_bdev, buffer);
    +}
    +
    +const struct squashfs_backend squashfs_bdev_ops = {
    + .init = bdev_init,
    + .free = bdev_free,
    + .read = bdev_read,
    + .probe = bdev_probe,
    + .kill = bdev_kill,
    + .size = bdev_size,
    + .devname= bdev_devname
    +};
    diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
    index d094886..0e74175 100644
    --- a/fs/squashfs/squashfs.h
    +++ b/fs/squashfs/squashfs.h
    @@ -73,8 +73,12 @@ extern struct inode *squashfs_iget(struct super_block *, long long,
    unsigned int);
    extern int squashfs_read_inode(struct inode *, long long);

    +/* super.c
    +int squashfs_fill_super(struct super_block *, void *, int,
    + struct squashfs_backend *);
    +*/
    /*
    - * Inodes, files and decompressor operations
    + * Inodes, files, backend and decompressor operations
    */

    /* dir.c */
    @@ -97,3 +101,6 @@ extern const struct squashfs_decompressor squashfs_zlib_comp_ops;

    /* lzma wrapper.c */
    extern const struct squashfs_decompressor squashfs_lzma_comp_ops;
    +
    +/* bdev.c */
    +extern const struct squashfs_backend squashfs_bdev_ops;
    diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h
    index 7533350..5662d9b 100644
    --- a/fs/squashfs/squashfs_fs_sb.h
    +++ b/fs/squashfs/squashfs_fs_sb.h
    @@ -53,6 +53,8 @@ struct squashfs_cache_entry {

    struct squashfs_sb_info {
    const struct squashfs_decompressor *decompressor;
    + const struct squashfs_backend *backend;
    + void *backend_data;
    int devblksize;
    int devblksize_log2;
    struct squashfs_cache *block_cache;
    --
    1.5.6.5

    From 3d469f3f3f2ecaacc8d99a142899216879099867 Mon Sep 17 00:00:00 2001
    From: Ferenc Wagner <wferi@niif.hu>
    Date: Sat, 20 Mar 2010 15:58:21 +0100
    Subject: [PATCH] squashfs: thread initialization through the backend framework

    This necessitated introducing the killsb callback.
    The read path is still untouched.
    ---
    fs/squashfs/backend.c | 22 +++++++++++++++-----
    fs/squashfs/backend.h | 11 ++++-----
    fs/squashfs/bdev.c | 3 +-
    fs/squashfs/squashfs.h | 6 ++--
    fs/squashfs/super.c | 49 +++++++++++++++++++++--------------------------
    5 files changed, 48 insertions(+), 43 deletions(-)
    diff --git a/fs/squashfs/backend.c b/fs/squashfs/backend.c
    index 4411c60..49fa6fa 100644
    --- a/fs/squashfs/backend.c
    +++ b/fs/squashfs/backend.c
    @@ -11,14 +11,24 @@ const struct squashfs_backend *backends[] = {
    NULL
    };

    -const struct squashfs_backend *
    -squashfs_find_backend(struct file_system_type *fs_type, int flags,
    +int squashfs_find_backend(struct file_system_type *fs_type, int flags,
    const char *dev_name, void *data, struct vfsmount *mnt)
    {
    const struct squashfs_backend **b;
    + int err;

    - for (b = backends; *b; b++)
    - if (!(*b)->probe(fs_type, flags, dev_name, data, mnt))
    - break;
    - return *b;
    + for (b = backends; *b; b++) {
    + err = (*b)->probe(fs_type, flags, dev_name, data, mnt);
    + if (!err)
    + return 0;
    + }
    + ERROR("No suitable backend found\n");
    + return -ENODEV;
    +}
    +
    +void squashfs_kill_super(struct super_block *sb)
    +{
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    +
    + msblk->backend->killsb(sb);
    }
    diff --git a/fs/squashfs/backend.h b/fs/squashfs/backend.h
    index ca3ffe1..02c4bcd 100644
    --- a/fs/squashfs/backend.h
    +++ b/fs/squashfs/backend.h
    @@ -9,14 +9,13 @@ struct squashfs_backend {
    ssize_t (*read)(struct squashfs_sb_info *, void **, size_t);
    int (*probe)(struct file_system_type *, int, const char *,
    void*, struct vfsmount *);
    + void (*killsb)(struct super_block *);
    void (*kill)(struct squashfs_sb_info *);
    loff_t (*size)(const struct super_block *);
    const char *(*devname)(const struct super_block *, char *);
    };

    -/* Dummy, until the original is nuked */
    -static inline int squashfs_fill_super2(struct super_block *sb, void *data,
    - int silent, int (*add_bend)(struct super_block *))
    -{
    - return -1;
    -}
    +int squashfs_find_backend(struct file_system_type *, int,
    + const char *, void *, struct vfsmount *);
    +
    +void squashfs_kill_super(struct super_block *);
    diff --git a/fs/squashfs/bdev.c b/fs/squashfs/bdev.c
    index c1d4389..0ee09f8 100644
    --- a/fs/squashfs/bdev.c
    +++ b/fs/squashfs/bdev.c
    @@ -69,7 +69,7 @@ static int add_bdev_backend(struct super_block *sb)

    static int fill_bdev_super(struct super_block *sb, void *data, int silent)
    {
    - return squashfs_fill_super2(sb, data, silent, add_bdev_backend);
    + return squashfs_fill_super(sb, data, silent, add_bdev_backend);
    }

    static int bdev_probe(struct file_system_type *fs_type, int flags,
    @@ -104,6 +104,7 @@ const struct squashfs_backend squashfs_bdev_ops = {
    .free = bdev_free,
    .read = bdev_read,
    .probe = bdev_probe,
    + .killsb = kill_block_super,
    .kill = bdev_kill,
    .size = bdev_size,
    .devname= bdev_devname
    diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
    index 0e74175..24c4b9e 100644
    --- a/fs/squashfs/squashfs.h
    +++ b/fs/squashfs/squashfs.h
    @@ -73,10 +73,10 @@ extern struct inode *squashfs_iget(struct super_block *, long long,
    unsigned int);
    extern int squashfs_read_inode(struct inode *, long long);

    -/* super.c
    +/* super.c */
    int squashfs_fill_super(struct super_block *, void *, int,
    - struct squashfs_backend *);
    -*/
    + int (*)(struct super_block *));
    +
    /*
    * Inodes, files, backend and decompressor operations
    */
    diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
    index 3550aec..710179f 100644
    --- a/fs/squashfs/super.c
    +++ b/fs/squashfs/super.c
    @@ -42,6 +42,7 @@
    #include "squashfs_fs_i.h"
    #include "squashfs.h"
    #include "decompressor.h"
    +#include "backend.h"

    static struct file_system_type squashfs_fs_type;
    static const struct super_operations squashfs_super_ops;
    @@ -73,7 +74,8 @@ static const struct squashfs_decompressor *supported_squashfs_filesystem(short
    }


    -static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
    +int squashfs_fill_super(struct super_block *sb, void *data, int silent,
    + int (*add_backend)(struct super_block *))
    {
    struct squashfs_sb_info *msblk;
    struct squashfs_super_block *sblk = NULL;
    @@ -97,11 +99,15 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
    sblk = kzalloc(sizeof(*sblk), GFP_KERNEL);
    if (sblk == NULL) {
    ERROR("Failed to allocate squashfs_super_block\n");
    - goto failure;
    + err = -ENOMEM;
    + goto free_msblk;
    }

    msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE);
    msblk->devblksize_log2 = ffz(~msblk->devblksize);
    + err = add_backend(sb);
    + if (err)
    + goto free_sblk;

    mutex_init(&msblk->read_data_mutex);
    mutex_init(&msblk->meta_index_mutex);
    @@ -127,7 +133,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
    if (sb->s_magic != SQUASHFS_MAGIC) {
    if (!silent)
    ERROR("Can't find a SQUASHFS superblock on %s\n",
    - bdevname(sb->s_bdev, b));
    + msblk->backend->devname(sb, b));
    goto failed_mount;
    }

    @@ -146,11 +152,10 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
    if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK)
    ERROR("Xattrs in filesystem, these will be ignored\n");

    - /* Check the filesystem does not extend beyond the end of the
    - block device */
    + /* Check the filesystem does not extend beyond the end of the device */
    msblk->bytes_used = le64_to_cpu(sblk->bytes_used);
    if (msblk->bytes_used < 0 || msblk->bytes_used >
    - i_size_read(sb->s_bdev->bd_inode))
    + msblk->backend->size(sb))
    goto failed_mount;

    /* Check block size for sanity */
    @@ -182,7 +187,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
    msblk->inodes = le32_to_cpu(sblk->inodes);
    flags = le16_to_cpu(sblk->flags);

    - TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b));
    + TRACE("Found valid superblock on %s\n", msblk->backend->devname(sb, b));
    TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags)
    ? "un" : "");
    TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags)
    @@ -297,18 +302,16 @@ failed_mount:
    squashfs_cache_delete(msblk->fragment_cache);
    squashfs_cache_delete(msblk->read_page);
    squashfs_decompressor_free(msblk, msblk->stream);
    - kfree(msblk->inode_lookup_table);
    + kfree(msblk->inode_lookup_table); /* FIXME: squashfs_put_super has meta_index instead */
    kfree(msblk->fragment_index);
    kfree(msblk->id_table);
    - kfree(sb->s_fs_info);
    - sb->s_fs_info = NULL;
    + msblk->backend->kill(msblk);
    +free_sblk:
    kfree(sblk);
    - return err;
    -
    -failure:
    - kfree(sb->s_fs_info);
    +free_msblk:
    + kfree(msblk);
    sb->s_fs_info = NULL;
    - return -ENOMEM;
    + return err;
    }


    @@ -353,7 +356,8 @@ static void squashfs_put_super(struct super_block *sb)
    kfree(sbi->id_table);
    kfree(sbi->fragment_index);
    kfree(sbi->meta_index);
    - kfree(sb->s_fs_info);
    + sbi->backend->kill(sbi);
    + kfree(sbi);
    sb->s_fs_info = NULL;
    }

    @@ -361,15 +365,6 @@ static void squashfs_put_super(struct super_block *sb)
    }


    -static int squashfs_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, squashfs_fill_super,
    - mnt);
    -}
    -
    -
    static struct kmem_cache *squashfs_inode_cachep;


    @@ -442,8 +437,8 @@ static void squashfs_destroy_inode(struct inode *inode)
    static struct file_system_type squashfs_fs_type = {
    .owner = THIS_MODULE,
    .name = "squashfs",
    - .get_sb = squashfs_get_sb,
    - .kill_sb = kill_block_super,
    + .get_sb = squashfs_find_backend,
    + .kill_sb = squashfs_kill_super,
    .fs_flags = FS_REQUIRES_DEV
    };

    --
    1.5.6.5

    From 32d8c56b48b79a37a2b8204c1a14767287ea6044 Mon Sep 17 00:00:00 2001
    From: Ferenc Wagner <wferi@niif.hu>
    Date: Sun, 21 Mar 2010 02:08:58 +0100
    Subject: [PATCH] squashfs: read uncompressed blocks through the backend framework

    Avoid double free on the temporary decompression hack-path; this may
    leak buffer heads if decompression exits early.
    ---
    fs/squashfs/backend.h | 4 +-
    fs/squashfs/bdev.c | 191 ++++++++++++++++++++++++++++++++++++++----
    fs/squashfs/block.c | 167 ++++++++-----------------------------
    fs/squashfs/lzma_wrapper.c | 2 +
    fs/squashfs/squashfs_fs_sb.h | 2 -
    fs/squashfs/super.c | 5 +-
    6 files changed, 216 insertions(+), 155 deletions(-)
    diff --git a/fs/squashfs/backend.h b/fs/squashfs/backend.h
    index 02c4bcd..308fe6d 100644
    --- a/fs/squashfs/backend.h
    +++ b/fs/squashfs/backend.h
    @@ -4,9 +4,9 @@
    #include "squashfs_fs_sb.h"

    struct squashfs_backend {
    - void *(*init)(struct squashfs_sb_info *, u64, size_t);
    + int (*init)(struct super_block *, u64, int, int, u64 *, int *);
    void (*free)(struct squashfs_sb_info *);
    - ssize_t (*read)(struct squashfs_sb_info *, void **, size_t);
    + int (*read)(struct super_block *, void *, int);
    int (*probe)(struct file_system_type *, int, const char *,
    void*, struct vfsmount *);
    void (*killsb)(struct super_block *);
    diff --git a/fs/squashfs/bdev.c b/fs/squashfs/bdev.c
    index 0ee09f8..497029b 100644
    --- a/fs/squashfs/bdev.c
    +++ b/fs/squashfs/bdev.c
    @@ -8,47 +8,200 @@
    struct squashfs_bdev {
    int devblksize; /* FIXME: == s->s_blocksize(_bits)? */
    unsigned short devblksize_log2;
    - size_t bytes_left;
    + int length;
    + int bytes_read;
    struct buffer_head **bh;
    int bh_index; /* number of consumed buffer_heads */
    int offset; /* offset of next byte in buffer_head */
    + int b; /* total number of buffer heads */
    };

    -/* A backend is initialized for each SquashFS block read operation,
    - * making further sequential reads possible from the block.
    +/*
    + * Read the metadata block length, this is stored in the first two
    + * bytes of the metadata block.
    */
    -static void *bdev_init(struct squashfs_sb_info *msblk, u64 index, size_t length)
    +static struct buffer_head *get_block_length(struct super_block *sb,
    + u64 *cur_index, int *offset, int *length)
    {
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    struct squashfs_bdev *bdev = msblk->backend_data;
    struct buffer_head *bh;

    + TRACE("get_block_length: cur_index=0x%llx, offset=%d\n",
    + (unsigned long long)*cur_index, *offset);
    + bh = sb_bread(sb, *cur_index);
    + if (bh == NULL)
    + return NULL;
    +
    + if (bdev->devblksize - *offset == 1) {
    + *length = (unsigned char) bh->b_data[*offset];
    + put_bh(bh);
    + bh = sb_bread(sb, ++(*cur_index));
    + if (bh == NULL)
    + return NULL;
    + *length |= (unsigned char) bh->b_data[0] << 8;
    + *offset = 1;
    + } else {
    + *length = (unsigned char) bh->b_data[*offset] |
    + (unsigned char) bh->b_data[*offset + 1] << 8;
    + *offset += 2;
    + }
    +
    + TRACE("get_block_length: length=%d, offset=%d\n", *length, *offset);
    + return bh;
    +}
    +
    +/*
    + * Read a metadata block or datablock into memory. Length is non-zero
    + * if a datablock is being read (the size is stored elsewhere in the
    + * filesystem), otherwise the length is obtained from the first two bytes of
    + * the metadata block. A bit in the length field indicates if the block
    + * is stored uncompressed in the filesystem (usually because compression
    + * generated a larger block - this does occasionally happen with zlib).
    + */
    +static int bdev_init(struct super_block *sb, u64 index, int length,
    + int srclength, u64 *next_index, int *compressed)
    +{
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    + struct squashfs_bdev *bdev = msblk->backend_data;
    + struct buffer_head **bh;
    + u64 cur_index; /* sector of next byte */
    + int bytes; /* number of bytes handled */
    + int b; /* for counting buffer heads */
    +
    + TRACE("Entering bdev_init: index=0x%llx, length=0x%x, srclength=%d\n",
    + index, length, srclength);
    bh = kcalloc((max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE)
    >> bdev->devblksize_log2) + 1,
    sizeof(*bh), GFP_KERNEL);
    - if (!bh)
    - goto nomem;
    + if (bh == NULL)
    + return -ENOMEM;
    +
    + bdev->offset = index & ((1 << bdev->devblksize_log2) - 1);
    + cur_index = index >> bdev->devblksize_log2;
    + if (length) { /* FIXME: this logic and the comment above should be pulled out! */
    + /*
    + * Datablock.
    + */
    + bytes = -bdev->offset;
    + *compressed = SQUASHFS_COMPRESSED_BLOCK(length);
    + length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
    + if (next_index)
    + *next_index = index + length;
    +
    + TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
    + index, *compressed ? "" : "un", length, srclength);

    - /* different preread for data blocks and metadata blocks */
    + if (length < 0 || length > srclength ||
    + (index + length) > msblk->bytes_used)
    + goto read_failure;

    + for (b = 0; bytes < length; b++, cur_index++) {
    + bh[b] = sb_getblk(sb, cur_index);
    + if (bh[b] == NULL)
    + goto block_release;
    + bytes += bdev->devblksize;
    + }
    + ll_rw_block(READ, b, bh);
    + } else {
    + /*
    + * Metadata block.
    + */
    + if ((index + 2) > msblk->bytes_used)
    + goto read_failure;
    +
    + bh[0] = get_block_length(sb, &cur_index, &bdev->offset, &length);
    + if (bh[0] == NULL)
    + goto read_failure;
    + b = 1;
    +
    + bytes = bdev->devblksize - bdev->offset;
    + *compressed = SQUASHFS_COMPRESSED(length);
    + length = SQUASHFS_COMPRESSED_SIZE(length);
    + if (next_index)
    + *next_index = index + length + 2;
    +
    + TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
    + *compressed ? "" : "un", length);
    +
    + if (length < 0 || length > srclength ||
    + (index + length) > msblk->bytes_used)
    + goto block_release;
    +
    + for (; bytes < length; b++) {
    + bh[b] = sb_getblk(sb, ++cur_index);
    + if (bh[b] == NULL)
    + goto block_release;
    + bytes += bdev->devblksize;
    + }
    + ll_rw_block(READ, b - 1, bh + 1);
    + }
    +
    + bdev->bh = bh;
    + bdev->length = length;
    + bdev->bytes_read = 0;
    + bdev->b = b;
    bdev->bh_index = 0;
    - bdev->bytes_left = length;
    - return bdev;
    + TRACE("bdev_init: allocated %d buffer heads at %p, returning length=%d",
    + b, bh, length);
    + return length;

    -nomem:
    - ERROR("failed to allocate buffer_heads\n");
    - return NULL;
    +block_release:
    + while (b--)
    + put_bh(bh[b]);
    +read_failure:
    + ERROR("bdev_init failed to read block 0x%llx\n",
    + (unsigned long long) index);
    + kfree(bh);
    + return -EIO;
    }

    static void bdev_free(struct squashfs_sb_info *msblk)
    {
    struct squashfs_bdev *bdev = msblk->backend_data;
    +
    + TRACE("bdev_free: bh=%p, bh_index=%d, b=%d\n",
    + bdev->bh, bdev->bh_index, bdev->b);
    + while (bdev->bh_index < bdev->b)
    + put_bh(bdev->bh[bdev->bh_index++]);
    kfree(bdev->bh);
    - bdev->bh = 0; /* FIXME: to make bdev_kill universal (see there) */
    + bdev->bh = NULL;
    }

    -static ssize_t bdev_read(struct squashfs_sb_info *msblk, void **buf, size_t len)
    +static int bdev_read(struct super_block *sb, void *buf, int len)
    {
    - return -ENOSYS;
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    + struct squashfs_bdev *bdev = msblk->backend_data;
    + struct buffer_head *bh = bdev->bh[bdev->bh_index];
    + int in_block = bdev->devblksize - bdev->offset;
    +
    + TRACE("bdev_read: buf=%p, len=%d, length=%d, bytes_read=%d, in_block=%d, bh_index=%d, offset=%d\n",
    + buf, len, bdev->length, bdev->bytes_read, in_block, bdev->bh_index, bdev->offset);
    + if (bdev->bytes_read == bdev->length) /* EOF */
    + return 0;
    + if (bdev->bytes_read + len > bdev->length)
    + len = bdev->length - bdev->bytes_read;
    + if (bdev->bytes_read == 0 || bdev->offset == 0) {
    + TRACE("bdev_read: wait_on_buffer %d\n", bdev->bh_index);
    + wait_on_buffer(bh);
    + if (!buffer_uptodate(bh))
    + return -EIO;
    + }
    + if (len < in_block) {
    + TRACE("bdev_read: copying %d bytes", len);
    + memcpy(buf, bh->b_data + bdev->offset, len);
    + bdev->offset += len;
    + bdev->bytes_read += len;
    + return len;
    + } else {
    + TRACE("bdev_read: copying %d bytes", in_block);
    + memcpy(buf, bh->b_data + bdev->offset, in_block);
    + put_bh(bh);
    + bdev->bh_index++;
    + bdev->offset = 0;
    + bdev->bytes_read += in_block;
    + return in_block;
    + }
    }

    static int add_bdev_backend(struct super_block *sb)
    @@ -56,6 +209,7 @@ static int add_bdev_backend(struct super_block *sb)
    struct squashfs_sb_info *msblk = sb->s_fs_info;
    struct squashfs_bdev *bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);

    + TRACE("add_bdev_backend\n");
    if (!bdev)
    return -ENOMEM;

    @@ -83,9 +237,12 @@ static int bdev_probe(struct file_system_type *fs_type, int flags,
    static void bdev_kill(struct squashfs_sb_info *msblk)
    {
    struct squashfs_bdev *bdev = msblk->backend_data;
    +
    + TRACE("bdev_kill: bdev=%p\n", bdev);
    if (bdev) {
    - kfree(bdev->bh); /* FIXME: can this be nonzero? cf. bdev_free */
    + bdev_free(msblk);
    kfree(bdev);
    + bdev = NULL;
    }
    }

    @@ -105,7 +262,7 @@ const struct squashfs_backend squashfs_bdev_ops = {
    .read = bdev_read,
    .probe = bdev_probe,
    .killsb = kill_block_super,
    - .kill = bdev_kill,
    + .kill = bdev_kill, /* FIXME: is this needed at all? */
    .size = bdev_size,
    .devname= bdev_devname
    };
    diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
    index 6f9914d..8787aac 100644
    --- a/fs/squashfs/block.c
    +++ b/fs/squashfs/block.c
    @@ -37,37 +37,19 @@
    #include "squashfs_fs_i.h"
    #include "squashfs.h"
    #include "decompressor.h"
    -/*
    - * Read the metadata block length, this is stored in the first two
    - * bytes of the metadata block.
    - */
    -static struct buffer_head *get_block_length(struct super_block *sb,
    - u64 *cur_index, int *offset, int *length)
    -{
    - struct squashfs_sb_info *msblk = sb->s_fs_info;
    - struct buffer_head *bh;
    -
    - bh = sb_bread(sb, *cur_index);
    - if (bh == NULL)
    - return NULL;
    -
    - if (msblk->devblksize - *offset == 1) {
    - *length = (unsigned char) bh->b_data[*offset];
    - put_bh(bh);
    - bh = sb_bread(sb, ++(*cur_index));
    - if (bh == NULL)
    - return NULL;
    - *length |= (unsigned char) bh->b_data[0] << 8;
    - *offset = 1;
    - } else {
    - *length = (unsigned char) bh->b_data[*offset] |
    - (unsigned char) bh->b_data[*offset + 1] << 8;
    - *offset += 2;
    - }
    -
    - return bh;
    -}
    -
    +#include "backend.h"
    +
    +/* FIXME: here for a temporary cheat only */
    +struct squashfs_bdev {
    + int devblksize; /* FIXME: == s->s_blocksize(_bits)? */
    + unsigned short devblksize_log2;
    + int length;
    + int bytes_read;
    + struct buffer_head **bh;
    + int bh_index; /* number of consumed buffer_heads */
    + int offset; /* offset of next byte in buffer_head */
    + int b; /* total number of buffer heads */
    +};

    /*
    * Read and decompress a metadata block or datablock. Length is non-zero
    @@ -80,124 +62,47 @@ static struct buffer_head *get_block_length(struct super_block *sb,
    int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
    int length, u64 *next_index, int srclength, int pages)
    {
    + int compressed;
    struct squashfs_sb_info *msblk = sb->s_fs_info;
    - struct buffer_head **bh;
    - int offset = index & ((1 << msblk->devblksize_log2) - 1);
    - u64 cur_index = index >> msblk->devblksize_log2;
    - int bytes, compressed, b = 0, k = 0, page = 0, avail;
    -
    -
    - bh = kcalloc((msblk->block_size >> msblk->devblksize_log2) + 1,
    - sizeof(*bh), GFP_KERNEL);
    - if (bh == NULL)
    - return -ENOMEM;
    -
    - if (length) {
    - /*
    - * Datablock.
    - */
    - bytes = -offset;
    - compressed = SQUASHFS_COMPRESSED_BLOCK(length);
    - length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
    - if (next_index)
    - *next_index = index + length;
    -
    - TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
    - index, compressed ? "" : "un", length, srclength);

    - if (length < 0 || length > srclength ||
    - (index + length) > msblk->bytes_used)
    - goto read_failure;
    -
    - for (b = 0; bytes < length; b++, cur_index++) {
    - bh[b] = sb_getblk(sb, cur_index);
    - if (bh[b] == NULL)
    - goto block_release;
    - bytes += msblk->devblksize;
    - }
    - ll_rw_block(READ, b, bh);
    - } else {
    - /*
    - * Metadata block.
    - */
    - if ((index + 2) > msblk->bytes_used)
    - goto read_failure;
    -
    - bh[0] = get_block_length(sb, &cur_index, &offset, &length);
    - if (bh[0] == NULL)
    - goto read_failure;
    - b = 1;
    -
    - bytes = msblk->devblksize - offset;
    - compressed = SQUASHFS_COMPRESSED(length);
    - length = SQUASHFS_COMPRESSED_SIZE(length);
    - if (next_index)
    - *next_index = index + length + 2;
    -
    - TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
    - compressed ? "" : "un", length);
    -
    - if (length < 0 || length > srclength ||
    - (index + length) > msblk->bytes_used)
    - goto block_release;
    -
    - for (; bytes < length; b++) {
    - bh[b] = sb_getblk(sb, ++cur_index);
    - if (bh[b] == NULL)
    - goto block_release;
    - bytes += msblk->devblksize;
    - }
    - ll_rw_block(READ, b - 1, bh + 1);
    - }
    + length = msblk->backend->init(sb, index, length, srclength,
    + next_index, &compressed);
    + if (length < 0)
    + return length;

    if (compressed) {
    - length = squashfs_decompress(msblk, buffer, bh, b, offset,
    - length, srclength, pages);
    + struct squashfs_bdev *bdev = msblk->backend_data;
    + length = squashfs_decompress(msblk, buffer, bdev->bh, bdev->b,
    + bdev->offset, length, srclength, pages);
    + bdev->bh_index = bdev->b; /* temporary hack to avoid double free */
    if (length < 0)
    goto read_failure;
    } else {
    /*
    * Block is uncompressed.
    */
    - int i, in, pg_offset = 0;
    -
    - for (i = 0; i < b; i++) {
    - wait_on_buffer(bh[i]);
    - if (!buffer_uptodate(bh[i]))
    - goto block_release;
    - }
    -
    - for (bytes = length; k < b; k++) {
    - in = min(bytes, msblk->devblksize - offset);
    - bytes -= in;
    - while (in) {
    - if (pg_offset == PAGE_CACHE_SIZE) {
    - page++;
    - pg_offset = 0;
    - }
    - avail = min_t(int, in, PAGE_CACHE_SIZE -
    - pg_offset);
    - memcpy(buffer[page] + pg_offset,
    - bh[k]->b_data + offset, avail);
    - in -= avail;
    - pg_offset += avail;
    - offset += avail;
    + int read, page = 0, pg_offset = 0;
    +
    + while ((read = msblk->backend->read(sb, buffer[page] + pg_offset,
    + PAGE_CACHE_SIZE - pg_offset))) {
    + if (read < 0)
    + goto read_failure;
    + TRACE("copied %d bytes\n", read);
    + pg_offset += read;
    + if (pg_offset == PAGE_CACHE_SIZE) {
    + page++;
    + pg_offset = 0;
    }
    - offset = 0;
    - put_bh(bh[k]);
    }
    }

    - kfree(bh);
    + msblk->backend->free(msblk);
    + TRACE("squashfs_read_data: returning length=%d\n", length);
    return length;

    -block_release:
    - for (; k < b; k++)
    - put_bh(bh[k]);
    -
    read_failure:
    ERROR("squashfs_read_data failed to read block 0x%llx\n",
    (unsigned long long) index);
    - kfree(bh);
    + msblk->backend->free(msblk);
    return -EIO;
    }
    diff --git a/fs/squashfs/lzma_wrapper.c b/fs/squashfs/lzma_wrapper.c
    index 9fa617d..439798f 100644
    --- a/fs/squashfs/lzma_wrapper.c
    +++ b/fs/squashfs/lzma_wrapper.c
    @@ -94,6 +94,8 @@ static int lzma_uncompress(struct squashfs_sb_info *msblk, void **buffer,
    void *buff = stream->input;
    int avail, i, bytes = length, res;

    + TRACE("lzma_uncompress: bh=%p, b=%d, offset=%d, length=%d, srclength=%d,"
    + " pages=%d\n", bh, b, offset, length, srclength, pages);
    mutex_lock(&lzma_mutex);

    for (i = 0; i < b; i++) {
    diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h
    index 5662d9b..87958fc 100644
    --- a/fs/squashfs/squashfs_fs_sb.h
    +++ b/fs/squashfs/squashfs_fs_sb.h
    @@ -55,8 +55,6 @@ struct squashfs_sb_info {
    const struct squashfs_decompressor *decompressor;
    const struct squashfs_backend *backend;
    void *backend_data;
    - int devblksize;
    - int devblksize_log2;
    struct squashfs_cache *block_cache;
    struct squashfs_cache *fragment_cache;
    struct squashfs_cache *read_page;
    diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
    index 710179f..cb561bf 100644
    --- a/fs/squashfs/super.c
    +++ b/fs/squashfs/super.c
    @@ -87,7 +87,7 @@ int squashfs_fill_super(struct super_block *sb, void *data, int silent,
    u64 lookup_table_start;
    int err;

    - TRACE("Entered squashfs_fill_superblock\n");
    + TRACE("Entered squashfs_fill_superblock, silent=%d\n", silent);

    sb->s_fs_info = kzalloc(sizeof(*msblk), GFP_KERNEL);
    if (sb->s_fs_info == NULL) {
    @@ -103,8 +103,6 @@ int squashfs_fill_super(struct super_block *sb, void *data, int silent,
    goto free_msblk;
    }

    - msblk->devblksize = sb_min_blocksize(sb, BLOCK_SIZE);
    - msblk->devblksize_log2 = ffz(~msblk->devblksize);
    err = add_backend(sb);
    if (err)
    goto free_sblk;
    @@ -305,6 +303,7 @@ failed_mount:
    kfree(msblk->inode_lookup_table); /* FIXME: squashfs_put_super has meta_index instead */
    kfree(msblk->fragment_index);
    kfree(msblk->id_table);
    + TRACE("squasfs_fill_super: killing backend, err=%d\n", err);
    msblk->backend->kill(msblk);
    free_sblk:
    kfree(sblk);
    --
    1.5.6.5

    From 7bad4e58afdc8c5e21dafcd538a1390e30176b0a Mon Sep 17 00:00:00 2001
    From: Ferenc Wagner <wferi@niif.hu>
    Date: Sun, 21 Mar 2010 22:38:00 +0100
    Subject: [PATCH] squashfs: move the decompressors to the backend framework

    ---
    fs/squashfs/block.c | 17 +----------------
    fs/squashfs/decompressor.h | 12 +++++-------
    fs/squashfs/lzma_wrapper.c | 27 +++++++++------------------
    fs/squashfs/zlib_wrapper.c | 44 ++++++++++++++++++--------------------------
    4 files changed, 33 insertions(+), 67 deletions(-)
    diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
    index 8787aac..1c85063 100644
    --- a/fs/squashfs/block.c
    +++ b/fs/squashfs/block.c
    @@ -39,18 +39,6 @@
    #include "decompressor.h"
    #include "backend.h"

    -/* FIXME: here for a temporary cheat only */
    -struct squashfs_bdev {
    - int devblksize; /* FIXME: == s->s_blocksize(_bits)? */
    - unsigned short devblksize_log2;
    - int length;
    - int bytes_read;
    - struct buffer_head **bh;
    - int bh_index; /* number of consumed buffer_heads */
    - int offset; /* offset of next byte in buffer_head */
    - int b; /* total number of buffer heads */
    -};
    -
    /*
    * Read and decompress a metadata block or datablock. Length is non-zero
    * if a datablock is being read (the size is stored elsewhere in the
    @@ -71,10 +59,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
    return length;

    if (compressed) {
    - struct squashfs_bdev *bdev = msblk->backend_data;
    - length = squashfs_decompress(msblk, buffer, bdev->bh, bdev->b,
    - bdev->offset, length, srclength, pages);
    - bdev->bh_index = bdev->b; /* temporary hack to avoid double free */
    + length = squashfs_decompress(sb, buffer, length, pages);
    if (length < 0)
    goto read_failure;
    } else {
    diff --git a/fs/squashfs/decompressor.h b/fs/squashfs/decompressor.h
    index 7425f80..06b4233 100644
    --- a/fs/squashfs/decompressor.h
    +++ b/fs/squashfs/decompressor.h
    @@ -26,8 +26,7 @@
    struct squashfs_decompressor {
    void *(*init)(struct squashfs_sb_info *);
    void (*free)(void *);
    - int (*decompress)(struct squashfs_sb_info *, void **,
    - struct buffer_head **, int, int, int, int, int);
    + int (*decompress)(struct super_block *, void **, int, int);
    int id;
    char *name;
    int supported;
    @@ -45,11 +44,10 @@ static inline void squashfs_decompressor_free(struct squashfs_sb_info *msblk,
    msblk->decompressor->free(s);
    }

    -static inline int squashfs_decompress(struct squashfs_sb_info *msblk,
    - void **buffer, struct buffer_head **bh, int b, int offset, int length,
    - int srclength, int pages)
    +static inline int squashfs_decompress(struct super_block *sb,
    + void **buffer, int length, int pages)
    {
    - return msblk->decompressor->decompress(msblk, buffer, bh, b, offset,
    - length, srclength, pages);
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    + return msblk->decompressor->decompress(sb, buffer, length, pages);
    }
    #endif
    diff --git a/fs/squashfs/lzma_wrapper.c b/fs/squashfs/lzma_wrapper.c
    index 439798f..da571ce 100644
    --- a/fs/squashfs/lzma_wrapper.c
    +++ b/fs/squashfs/lzma_wrapper.c
    @@ -32,6 +32,7 @@
    #include "squashfs_fs_i.h"
    #include "squashfs.h"
    #include "decompressor.h"
    +#include "backend.h"

    struct squashfs_lzma {
    void *input;
    @@ -86,29 +87,23 @@ static void lzma_free(void *strm)
    }


    -static int lzma_uncompress(struct squashfs_sb_info *msblk, void **buffer,
    - struct buffer_head **bh, int b, int offset, int length, int srclength,
    - int pages)
    +static int lzma_uncompress(struct super_block *sb, void **buffer,
    + int length, int pages)
    {
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    struct squashfs_lzma *stream = msblk->stream;
    void *buff = stream->input;
    int avail, i, bytes = length, res;

    - TRACE("lzma_uncompress: bh=%p, b=%d, offset=%d, length=%d, srclength=%d,"
    - " pages=%d\n", bh, b, offset, length, srclength, pages);
    + TRACE("lzma_uncompress: length=%d, pages=%d\n", length, pages);
    mutex_lock(&lzma_mutex);

    - for (i = 0; i < b; i++) {
    - wait_on_buffer(bh[i]);
    - if (!buffer_uptodate(bh[i]))
    - goto block_release;
    -
    - avail = min(bytes, msblk->devblksize - offset);
    - memcpy(buff, bh[i]->b_data + offset, avail);
    + while ((avail = msblk->backend->read(sb, buff, length))) {
    + if (avail < 0)
    + goto failed;
    + TRACE("read %d bytes\n", avail);
    buff += avail;
    bytes -= avail;
    - offset = 0;
    - put_bh(bh[i]);
    }

    lzma_error = 0;
    @@ -131,10 +126,6 @@ static int lzma_uncompress(struct squashfs_sb_info *msblk, void **buffer,
    mutex_unlock(&lzma_mutex);
    return res;

    -block_release:
    - for (; i < b; i++)
    - put_bh(bh[i]);
    -
    failed:
    mutex_unlock(&lzma_mutex);

    diff --git a/fs/squashfs/zlib_wrapper.c b/fs/squashfs/zlib_wrapper.c
    index 4dd70e0..70c7571 100644
    --- a/fs/squashfs/zlib_wrapper.c
    +++ b/fs/squashfs/zlib_wrapper.c
    @@ -31,6 +31,7 @@
    #include "squashfs_fs_i.h"
    #include "squashfs.h"
    #include "decompressor.h"
    +#include "backend.h"

    static void *zlib_init(struct squashfs_sb_info *dummy)
    {
    @@ -61,13 +62,18 @@ static void zlib_free(void *strm)
    }


    -static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
    - struct buffer_head **bh, int b, int offset, int length, int srclength,
    - int pages)
    +static int zlib_uncompress(struct super_block *sb, void **buffer,
    + int length, int pages)
    {
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    int zlib_err = 0, zlib_init = 0;
    - int avail, bytes, k = 0, page = 0;
    + int bytes, page = 0;
    z_stream *stream = msblk->stream;
    + /* Copying is required by the backend interface for now. */
    + void *input = kmalloc (PAGE_CACHE_SIZE, GFP_KERNEL);
    +
    + if (!input)
    + return -ENOMEM;

    mutex_lock(&msblk->read_data_mutex);

    @@ -76,22 +82,13 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,

    bytes = length;
    do {
    - if (stream->avail_in == 0 && k < b) {
    - avail = min(bytes, msblk->devblksize - offset);
    - bytes -= avail;
    - wait_on_buffer(bh[k]);
    - if (!buffer_uptodate(bh[k]))
    + if (stream->avail_in == 0) {
    + stream->avail_in = msblk->backend->read(sb, input, PAGE_CACHE_SIZE);
    + if (!stream->avail_in) {
    + ERROR("unexpected end of input\n");
    goto release_mutex;
    -
    - if (avail == 0) {
    - offset = 0;
    - put_bh(bh[k++]);
    - continue;
    }
    -
    - stream->next_in = bh[k]->b_data + offset;
    - stream->avail_in = avail;
    - offset = 0;
    + stream->next_in = input;
    }

    if (stream->avail_out == 0 && page < pages) {
    @@ -103,8 +100,7 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
    zlib_err = zlib_inflateInit(stream);
    if (zlib_err != Z_OK) {
    ERROR("zlib_inflateInit returned unexpected "
    - "result 0x%x, srclength %d\n",
    - zlib_err, srclength);
    + "result 0x%x\n", zlib_err);
    goto release_mutex;
    }
    zlib_init = 1;
    @@ -112,8 +108,6 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,

    zlib_err = zlib_inflate(stream, Z_SYNC_FLUSH);

    - if (stream->avail_in == 0 && k < b)
    - put_bh(bh[k++]);
    } while (zlib_err == Z_OK);

    if (zlib_err != Z_STREAM_END) {
    @@ -128,14 +122,12 @@ static int zlib_uncompress(struct squashfs_sb_info *msblk, void **buffer,
    }

    mutex_unlock(&msblk->read_data_mutex);
    + kfree(input);
    return stream->total_out;

    release_mutex:
    mutex_unlock(&msblk->read_data_mutex);
    -
    - for (; k < b; k++)
    - put_bh(bh[k]);
    -
    + kfree(input);
    return -EIO;
    }

    --
    1.5.6.5

    From 9cb2a2373ab4b7a5519c5a2ef816894e28778196 Mon Sep 17 00:00:00 2001
    From: Ferenc Wagner <wferi@niif.hu>
    Date: Tue, 23 Mar 2010 02:21:27 +0100
    Subject: [PATCH] squashfs: add mtd backend

    ---
    fs/squashfs/Kconfig | 2 +-
    fs/squashfs/Makefile | 1 +
    fs/squashfs/backend.c | 3 +
    fs/squashfs/mtd.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++
    fs/squashfs/squashfs.h | 3 +
    5 files changed, 175 insertions(+), 1 deletions(-)
    create mode 100644 fs/squashfs/mtd.c
    diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig
    index 7ec5d7e..6849e70 100644
    --- a/fs/squashfs/Kconfig
    +++ b/fs/squashfs/Kconfig
    @@ -1,6 +1,6 @@
    config SQUASHFS
    tristate "SquashFS 4.0 - Squashed file system support"
    - depends on BLOCK
    + depends on BLOCK || MTD
    select ZLIB_INFLATE
    help
    Saying Y here includes support for SquashFS 4.0 (a Compressed
    diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile
    index 0f02891..b6dd60e 100644
    --- a/fs/squashfs/Makefile
    +++ b/fs/squashfs/Makefile
    @@ -7,3 +7,4 @@ squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
    squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o backend.o
    squashfs-$(CONFIG_SQUASHFS_LZMA) += lzma_wrapper.o
    squashfs-$(CONFIG_BLOCK) += bdev.o
    +squashfs-$(CONFIG_MTD) += mtd.o
    diff --git a/fs/squashfs/backend.c b/fs/squashfs/backend.c
    index 49fa6fa..56037e3 100644
    --- a/fs/squashfs/backend.c
    +++ b/fs/squashfs/backend.c
    @@ -8,6 +8,9 @@ const struct squashfs_backend *backends[] = {
    #ifdef CONFIG_BLOCK
    &squashfs_bdev_ops,
    #endif
    +#ifdef CONFIG_MTD
    + &squashfs_mtd_ops,
    +#endif
    NULL
    };

    diff --git a/fs/squashfs/mtd.c b/fs/squashfs/mtd.c
    new file mode 100644
    index 0000000..c9ba361
    --- /dev/null
    +++ b/fs/squashfs/mtd.c
    @@ -0,0 +1,167 @@
    +#include <linux/fs.h>
    +#include <linux/mtd/mtd.h>
    +#include <linux/mtd/super.h>
    +
    +#include "squashfs_fs_i.h"
    +#include "squashfs.h"
    +#include "backend.h"
    +
    +struct squashfs_mtd {
    + u64 index;
    + int length;
    + int bytes_read;
    +};
    +
    +static int checked_mtd_read(struct super_block *sb, u64 index, int length,
    + void *buf)
    +{
    + struct mtd_info *mi = sb->s_mtd;
    + int ret, retlen;
    +
    + TRACE("Entering checked_mtd_read: index=0x%llx, length=%d\n",
    + index, length);
    + ret = mi->read(mi, index, length, &retlen, buf);
    + if (ret) {
    + if (ret != -EUCLEAN && ret != -EBADMSG) {
    + ERROR("checked_mtd_read(index=0x%llx, length=%d): %d\n",
    + index, length, ret);
    + return ret;
    + } else
    + WARNING("checked_mtd_read(index=0x%llx, length=%d): "
    + "recoverable error %d\n", index, length, ret);
    + }
    + if (retlen != length) {
    + ERROR("checked_mtd_read(index=0x%llx, length=%d) short read: %d\n",
    + index, length, retlen);
    + return -EIO;
    + }
    + return 0;
    +}
    +
    +static int mtd_init(struct super_block *sb, u64 index, int length,
    + int srclength, u64 *next_index, int *compressed)
    +{
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    + struct squashfs_mtd *mtd = msblk->backend_data;
    +
    + TRACE("Entering mtd_init: index=0x%llx, length=0x%x, srclength=%d\n",
    + index, length, srclength);
    +
    + if (length) { /* datablock */
    + *compressed = SQUASHFS_COMPRESSED_BLOCK(length);
    + length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
    + if (next_index)
    + *next_index = index + length;
    + TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
    + index, *compressed ? "" : "un", length, srclength);
    + } else { /* metadata block */
    + u16 metalen;
    + if ((index + 2) > msblk->bytes_used)
    + goto read_failure;
    + if (checked_mtd_read(sb, index, 2, &metalen))
    + goto read_failure;
    + length = le16_to_cpu(metalen);
    + *compressed = SQUASHFS_COMPRESSED(length);
    + length = SQUASHFS_COMPRESSED_SIZE(length);
    + if (next_index)
    + *next_index = index + length + 2;
    + TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
    + *compressed ? "" : "un", length);
    + index += 2;
    + }
    + if (length < 0 || length > srclength ||
    + (index + length) > msblk->bytes_used)
    + goto read_failure;
    +
    + mtd->index = index;
    + mtd->length = length;
    + mtd->bytes_read = 0;
    + return length;
    +
    +read_failure:
    + ERROR("mtd_init failed to read block 0x%llx\n",
    + (unsigned long long) index);
    + return -EIO;
    +}
    +
    +static void mtd_free(struct squashfs_sb_info *msblk)
    +{
    + TRACE("mtd_free: no op\n");
    +}
    +
    +static int mtd_read(struct super_block *sb, void *buf, int len)
    +{
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    + struct squashfs_mtd *mtd = msblk->backend_data;
    + int err;
    +
    + TRACE("mtd_read: buf=%p, len=%d, length=%d, bytes_read=%d\n",
    + buf, len, mtd->length, mtd->bytes_read);
    +
    + if (mtd->bytes_read == mtd->length) /* EOF */
    + return 0;
    + if (mtd->bytes_read + len > mtd->length)
    + len = mtd->length - mtd->bytes_read;
    + TRACE("mtd_read: copying %d bytes", len);
    + err = checked_mtd_read(sb, mtd->index + mtd->bytes_read, len, buf);
    + if (err)
    + return err;
    + mtd->bytes_read += len;
    + return len;
    +}
    +
    +static int add_mtd_backend(struct super_block *sb)
    +{
    + struct squashfs_sb_info *msblk = sb->s_fs_info;
    + struct squashfs_mtd *mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
    +
    + TRACE("add_mtd_backend\n");
    + if (!mtd)
    + return -ENOMEM;
    +
    + msblk->backend = &squashfs_mtd_ops;
    + msblk->backend_data = mtd;
    + return 0;
    +}
    +
    +static int fill_mtd_super(struct super_block *sb, void *data, int silent)
    +{
    + return squashfs_fill_super(sb, data, silent, add_mtd_backend);
    +}
    +
    +static int mtd_probe(struct file_system_type *fs_type, int flags,
    + const char *dev_name, void *data,
    + struct vfsmount *mnt)
    +{
    + return get_sb_mtd(fs_type, flags, dev_name, data,
    + fill_mtd_super, mnt);
    +}
    +
    +static void mtd_kill(struct squashfs_sb_info *msblk)
    +{
    + TRACE("mtd_kill: mtd=%p\n", msblk->backend_data);
    + mtd_free(msblk);
    + kfree(msblk->backend_data);
    +}
    +
    +static loff_t mtd_size(const struct super_block *sb)
    +{
    + return sb->s_mtd->size;
    +}
    +
    +static const char *mtd_devname(const struct super_block *sb, char *buffer)
    +{
    + snprintf(buffer, BDEVNAME_SIZE, "MTD%d", sb->s_mtd->index);
    + return buffer;
    +}
    +
    +const struct squashfs_backend squashfs_mtd_ops = {
    + .init = mtd_init,
    + .free = mtd_free,
    + .read = mtd_read,
    + .probe = mtd_probe,
    + .killsb = kill_mtd_super,
    + .kill = mtd_kill,
    + .size = mtd_size,
    + .devname= mtd_devname
    +};
    diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h
    index 24c4b9e..fc3a57a 100644
    --- a/fs/squashfs/squashfs.h
    +++ b/fs/squashfs/squashfs.h
    @@ -104,3 +104,6 @@ extern const struct squashfs_decompressor squashfs_lzma_comp_ops;

    /* bdev.c */
    extern const struct squashfs_backend squashfs_bdev_ops;
    +
    +/* mtd.c */
    +extern const struct squashfs_backend squashfs_mtd_ops;
    --
    1.5.6.5

    From 294602c4fed7319aeb5c44fff5bb8649f1f37b6e Mon Sep 17 00:00:00 2001
    From: Ferenc Wagner <wferi@niif.hu>
    Date: Tue, 23 Mar 2010 10:21:40 +0100
    Subject: [PATCH] squashfs: pull out common logic of backend init functions

    ---
    fs/squashfs/backend.h | 2 +-
    fs/squashfs/bdev.c | 155 +++++++++----------------------------------------
    fs/squashfs/block.c | 33 ++++++++++-
    fs/squashfs/mtd.c | 38 +-----------
    4 files changed, 62 insertions(+), 166 deletions(-)
    diff --git a/fs/squashfs/backend.h b/fs/squashfs/backend.h
    index 308fe6d..5beba00 100644
    --- a/fs/squashfs/backend.h
    +++ b/fs/squashfs/backend.h
    @@ -4,7 +4,7 @@
    #include "squashfs_fs_sb.h"

    struct squashfs_backend {
    - int (*init)(struct super_block *, u64, int, int, u64 *, int *);
    + int (*init)(struct super_block *, u64, int);
    void (*free)(struct squashfs_sb_info *);
    int (*read)(struct super_block *, void *, int);
    int (*probe)(struct file_system_type *, int, const char *,
    diff --git a/fs/squashfs/bdev.c b/fs/squashfs/bdev.c
    index 497029b..20065b7 100644
    --- a/fs/squashfs/bdev.c
    +++ b/fs/squashfs/bdev.c
    @@ -16,156 +16,55 @@ struct squashfs_bdev {
    int b; /* total number of buffer heads */
    };

    -/*
    - * Read the metadata block length, this is stored in the first two
    - * bytes of the metadata block.
    - */
    -static struct buffer_head *get_block_length(struct super_block *sb,
    - u64 *cur_index, int *offset, int *length)
    +static void bdev_free(struct squashfs_sb_info *msblk)
    {
    - struct squashfs_sb_info *msblk = sb->s_fs_info;
    struct squashfs_bdev *bdev = msblk->backend_data;
    - struct buffer_head *bh;
    -
    - TRACE("get_block_length: cur_index=0x%llx, offset=%d\n",
    - (unsigned long long)*cur_index, *offset);
    - bh = sb_bread(sb, *cur_index);
    - if (bh == NULL)
    - return NULL;

    - if (bdev->devblksize - *offset == 1) {
    - *length = (unsigned char) bh->b_data[*offset];
    - put_bh(bh);
    - bh = sb_bread(sb, ++(*cur_index));
    - if (bh == NULL)
    - return NULL;
    - *length |= (unsigned char) bh->b_data[0] << 8;
    - *offset = 1;
    - } else {
    - *length = (unsigned char) bh->b_data[*offset] |
    - (unsigned char) bh->b_data[*offset + 1] << 8;
    - *offset += 2;
    - }
    -
    - TRACE("get_block_length: length=%d, offset=%d\n", *length, *offset);
    - return bh;
    + TRACE("bdev_free: bh=%p, bh_index=%d, b=%d\n",
    + bdev->bh, bdev->bh_index, bdev->b);
    + while (bdev->bh_index < bdev->b)
    + put_bh(bdev->bh[bdev->bh_index++]);
    + kfree(bdev->bh);
    + bdev->bh = NULL;
    }

    -/*
    - * Read a metadata block or datablock into memory. Length is non-zero
    - * if a datablock is being read (the size is stored elsewhere in the
    - * filesystem), otherwise the length is obtained from the first two bytes of
    - * the metadata block. A bit in the length field indicates if the block
    - * is stored uncompressed in the filesystem (usually because compression
    - * generated a larger block - this does occasionally happen with zlib).
    - */
    -static int bdev_init(struct super_block *sb, u64 index, int length,
    - int srclength, u64 *next_index, int *compressed)
    +static int bdev_init(struct super_block *sb, u64 index, int length)
    {
    struct squashfs_sb_info *msblk = sb->s_fs_info;
    struct squashfs_bdev *bdev = msblk->backend_data;
    - struct buffer_head **bh;
    u64 cur_index; /* sector of next byte */
    int bytes; /* number of bytes handled */
    - int b; /* for counting buffer heads */

    - TRACE("Entering bdev_init: index=0x%llx, length=0x%x, srclength=%d\n",
    - index, length, srclength);
    - bh = kcalloc((max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE)
    - >> bdev->devblksize_log2) + 1,
    - sizeof(*bh), GFP_KERNEL);
    - if (bh == NULL)
    + TRACE("Entering bdev_init: index=0x%llx, length=0x%x\n",
    + index, length);
    + bdev->bh = kcalloc((max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE)
    + >> bdev->devblksize_log2) + 1,
    + sizeof(*bdev->bh), GFP_KERNEL);
    + if (bdev->bh == NULL)
    return -ENOMEM;

    bdev->offset = index & ((1 << bdev->devblksize_log2) - 1);
    cur_index = index >> bdev->devblksize_log2;
    - if (length) { /* FIXME: this logic and the comment above should be pulled out! */
    - /*
    - * Datablock.
    - */
    - bytes = -bdev->offset;
    - *compressed = SQUASHFS_COMPRESSED_BLOCK(length);
    - length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
    - if (next_index)
    - *next_index = index + length;
    -
    - TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
    - index, *compressed ? "" : "un", length, srclength);
    -
    - if (length < 0 || length > srclength ||
    - (index + length) > msblk->bytes_used)
    - goto read_failure;
    -
    - for (b = 0; bytes < length; b++, cur_index++) {
    - bh[b] = sb_getblk(sb, cur_index);
    - if (bh[b] == NULL)
    - goto block_release;
    - bytes += bdev->devblksize;
    - }
    - ll_rw_block(READ, b, bh);
    - } else {
    - /*
    - * Metadata block.
    - */
    - if ((index + 2) > msblk->bytes_used)
    - goto read_failure;
    -
    - bh[0] = get_block_length(sb, &cur_index, &bdev->offset, &length);
    - if (bh[0] == NULL)
    - goto read_failure;
    - b = 1;
    -
    - bytes = bdev->devblksize - bdev->offset;
    - *compressed = SQUASHFS_COMPRESSED(length);
    - length = SQUASHFS_COMPRESSED_SIZE(length);
    - if (next_index)
    - *next_index = index + length + 2;

    - TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
    - *compressed ? "" : "un", length);
    -
    - if (length < 0 || length > srclength ||
    - (index + length) > msblk->bytes_used)
    - goto block_release;
    + bdev->bh_index = 0;
    + bdev->length = length;
    + bdev->bytes_read = 0;

    - for (; bytes < length; b++) {
    - bh[b] = sb_getblk(sb, ++cur_index);
    - if (bh[b] == NULL)
    - goto block_release;
    - bytes += bdev->devblksize;
    + bytes = -bdev->offset;
    + for (bdev->b = 0; bytes < length; bdev->b++, cur_index++) {
    + if ((bdev->bh[bdev->b] = sb_getblk(sb, cur_index)) == NULL) {
    + ERROR("bdev_init failed to read block 0x%llx\n",
    + (unsigned long long) index);
    + bdev_free(msblk);
    + return -EIO;
    }
    - ll_rw_block(READ, b - 1, bh + 1);
    + bytes += bdev->devblksize;
    }
    + ll_rw_block(READ, bdev->b, bdev->bh);

    - bdev->bh = bh;
    - bdev->length = length;
    - bdev->bytes_read = 0;
    - bdev->b = b;
    - bdev->bh_index = 0;
    TRACE("bdev_init: allocated %d buffer heads at %p, returning length=%d",
    - b, bh, length);
    + bdev->b, bdev->bh, length);
    return length;
    -
    -block_release:
    - while (b--)
    - put_bh(bh[b]);
    -read_failure:
    - ERROR("bdev_init failed to read block 0x%llx\n",
    - (unsigned long long) index);
    - kfree(bh);
    - return -EIO;
    -}
    -
    -static void bdev_free(struct squashfs_sb_info *msblk)
    -{
    - struct squashfs_bdev *bdev = msblk->backend_data;
    -
    - TRACE("bdev_free: bh=%p, bh_index=%d, b=%d\n",
    - bdev->bh, bdev->bh_index, bdev->b);
    - while (bdev->bh_index < bdev->b)
    - put_bh(bdev->bh[bdev->bh_index++]);
    - kfree(bdev->bh);
    - bdev->bh = NULL;
    }

    static int bdev_read(struct super_block *sb, void *buf, int len)
    diff --git a/fs/squashfs/block.c b/fs/squashfs/block.c
    index 1c85063..eb33770 100644
    --- a/fs/squashfs/block.c
    +++ b/fs/squashfs/block.c
    @@ -53,8 +53,37 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
    int compressed;
    struct squashfs_sb_info *msblk = sb->s_fs_info;

    - length = msblk->backend->init(sb, index, length, srclength,
    - next_index, &compressed);
    + if (length) { /* Data block */
    + compressed = SQUASHFS_COMPRESSED_BLOCK(length);
    + length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
    + TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
    + index, compressed ? "" : "un", length, srclength);
    + } else { /* Metadata block */
    + int read;
    + u16 metalen;
    +
    + length = msblk->backend->init(sb, index, 2);
    + if (length < 0)
    + return length;
    + read = msblk->backend->read(sb, &metalen, 2);
    + if (read != 2)
    + goto read_failure;
    + msblk->backend->free(msblk);
    + length = le16_to_cpu(metalen);
    + compressed = SQUASHFS_COMPRESSED(length);
    + length = SQUASHFS_COMPRESSED_SIZE(length);
    + index += 2;
    + TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
    + compressed ? "" : "un", length);
    + }
    + if (length < 0 || length > srclength ||
    + (index + length) > msblk->bytes_used)
    + goto read_failure;
    +
    + if (next_index)
    + *next_index = index + length;
    +
    + length = msblk->backend->init(sb, index, length);
    if (length < 0)
    return length;

    diff --git a/fs/squashfs/mtd.c b/fs/squashfs/mtd.c
    index c9ba361..99f2d35 100644
    --- a/fs/squashfs/mtd.c
    +++ b/fs/squashfs/mtd.c
    @@ -38,50 +38,18 @@ static int checked_mtd_read(struct super_block *sb, u64 index, int length,
    return 0;
    }

    -static int mtd_init(struct super_block *sb, u64 index, int length,
    - int srclength, u64 *next_index, int *compressed)
    +static int mtd_init(struct super_block *sb, u64 index, int length)
    {
    struct squashfs_sb_info *msblk = sb->s_fs_info;
    struct squashfs_mtd *mtd = msblk->backend_data;

    - TRACE("Entering mtd_init: index=0x%llx, length=0x%x, srclength=%d\n",
    - index, length, srclength);
    -
    - if (length) { /* datablock */
    - *compressed = SQUASHFS_COMPRESSED_BLOCK(length);
    - length = SQUASHFS_COMPRESSED_SIZE_BLOCK(length);
    - if (next_index)
    - *next_index = index + length;
    - TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
    - index, *compressed ? "" : "un", length, srclength);
    - } else { /* metadata block */
    - u16 metalen;
    - if ((index + 2) > msblk->bytes_used)
    - goto read_failure;
    - if (checked_mtd_read(sb, index, 2, &metalen))
    - goto read_failure;
    - length = le16_to_cpu(metalen);
    - *compressed = SQUASHFS_COMPRESSED(length);
    - length = SQUASHFS_COMPRESSED_SIZE(length);
    - if (next_index)
    - *next_index = index + length + 2;
    - TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
    - *compressed ? "" : "un", length);
    - index += 2;
    - }
    - if (length < 0 || length > srclength ||
    - (index + length) > msblk->bytes_used)
    - goto read_failure;
    + TRACE("Entering mtd_init: index=0x%llx, length=0x%x\n",
    + index, length);

    mtd->index = index;
    mtd->length = length;
    mtd->bytes_read = 0;
    return length;
    -
    -read_failure:
    - ERROR("mtd_init failed to read block 0x%llx\n",
    - (unsigned long long) index);
    - return -EIO;
    }

    static void mtd_free(struct squashfs_sb_info *msblk)
    --
    1.5.6.5
    \
     
     \ /
      Last update: 2010-03-23 21:51    [W:0.126 / U:37.120 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site