Пример #1
0
/******************************************************************************
 *
 * axfs_put_super
 *
 * Description:
 *      After testing various mounting options and media mounts the image
 *
 * Parameters:
 *    (IN) sb - pointer to the super block
 *
 * Returns:
 *    none
 *
 *****************************************************************************/
static void axfs_put_super(struct super_block *sb)
{
	struct axfs_super_incore *sbi = AXFS_SB(sb);

#ifdef CONFIG_AXFS_PROFILING
	shutdown_axfs_profiling(sbi);
#endif

	vfree(sbi->metadata);

    axfs_free_region(sbi,&sbi->strings);
    axfs_free_region(sbi,&sbi->xip);
    axfs_free_region(sbi,&sbi->compressed);
    axfs_free_region(sbi,&sbi->byte_aligned);
    axfs_free_region(sbi,&sbi->node_type);
    axfs_free_region(sbi,&sbi->node_index);
    axfs_free_region(sbi,&sbi->cnode_offset);
    axfs_free_region(sbi,&sbi->cnode_index);
    axfs_free_region(sbi,&sbi->banode_offset);
    axfs_free_region(sbi,&sbi->cblock_offset);
    axfs_free_region(sbi,&sbi->inode_file_size);
    axfs_free_region(sbi,&sbi->inode_name_offset);
    axfs_free_region(sbi,&sbi->inode_num_entries);
    axfs_free_region(sbi,&sbi->inode_mode_index);
    axfs_free_region(sbi,&sbi->inode_array_index);
    axfs_free_region(sbi,&sbi->modes);
    axfs_free_region(sbi,&sbi->uids);
    axfs_free_region(sbi,&sbi->gids);

	vfree(sbi->cblock_buffer[0]);
	vfree(sbi->cblock_buffer[1]);

	vfree(sbi);
	sbi = NULL;
}
Пример #2
0
/******************************************************************************
 *
 * axfs_fetch_data
 *
 * Description:
 *   Copies data from the media, memory or block dev, to a buffer.
 *
 * Parameters:
 *    (IN) sb- superblock pointer
 *
 *    (IN) fofffset - offset from the beginning of the filesystem
 *
 *    (IN) len - length to be fetched
 *
 * Returns:
 *    a vmalloc()'ed pointer with a copy of the requested data
 *
 *****************************************************************************/
static void *axfs_fetch_data(struct super_block *sb, u64 fsoffset, u64 len) {
	struct axfs_super_incore *sbi = AXFS_SB(sb);
	u64 boffset;
	u64 end;
	u64 mmap_buffer_len;
	u64 blk_buffer_len;
	void *mmap_buffer;
	void *blk_buffer;
	void *return_buffer;

	end = fsoffset + len;

	if(AXFS_IS_OFFSET_MMAPABLE(sbi,fsoffset)){
		if(AXFS_IS_OFFSET_MMAPABLE(sbi,end))
			return axfs_fetch_mmapable_data(sbi,fsoffset,len);
		mmap_buffer_len = sbi->mmap_size - fsoffset;
		mmap_buffer = axfs_fetch_mmapable_data(sbi,fsoffset, mmap_buffer_len);
		blk_buffer_len = end - sbi->mmap_size;
		blk_buffer = axfs_fetch_block_data(sb, 0, blk_buffer_len);
		return_buffer = vmalloc((size_t)len);
		memcpy(return_buffer, mmap_buffer, mmap_buffer_len);
		memcpy((void *)((unsigned long)return_buffer + (unsigned long)mmap_buffer_len), blk_buffer, blk_buffer_len);
		vfree(blk_buffer);
		vfree(mmap_buffer);
		return return_buffer;
	}
	boffset = AXFS_FSOFFSET_2_BLOCKOFFSET(sbi,fsoffset);
	return axfs_fetch_block_data(sb, boffset, len);
}
Пример #3
0
static void axfs_copy_mem(struct super_block *sb, void *buf, u64 fsoffset,
                          u64 len)
{
    struct axfs_super *sbi = AXFS_SB(sb);
    unsigned long addr;

    addr = sbi->virt_start_addr + (unsigned long)fsoffset;

    memcpy(buf, (void *)addr, (size_t) len);
}
Пример #4
0
static void axfs_put_super(struct super_block *sb)
{
#ifndef NO_PHYSMEM
    /* Grab our remapped address before we blow away sbi */
    void *addr = axfs_get_physmem_addr(sb);
#endif
    axfs_unmap_mtd(sb);
    axfs_put_sbi(AXFS_SB(sb));
    sb->s_fs_info = NULL;
#ifndef NO_PHYSMEM
    axfs_unmap_physmem(addr);
#endif
}
Пример #5
0
/******************************************************************************
 *
 * axfs_statfs
 *
 * Description:
 *      Returns fs stats which are static
 *
 *****************************************************************************/
static int axfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	struct axfs_super_incore *sbi = AXFS_SB(dentry->d_sb);

	buf->f_type = AXFS_MAGIC;
	buf->f_bsize = PAGE_CACHE_SIZE;
	buf->f_blocks = sbi->blocks;
	buf->f_bfree = 0;
	buf->f_bavail = 0;
	buf->f_files = sbi->files;
	buf->f_ffree = 0;
	buf->f_namelen = AXFS_MAXPATHLEN;
	return 0;
}
Пример #6
0
static int axfs_do_fill_super(struct super_block *sb)
{
    struct axfs_super *sbi = AXFS_SB(sb);
    int err;

    err = axfs_get_onmedia_super(sb);
    if (err)
        goto out;

    err = axfs_fixup_devices(sb);
    if (err)
        goto out;

    err = axfs_verify_device_sizes(sb);
    if (err)
        goto out;

    err = axfs_verify_eofs_magic(sb);
    if (err)
        goto out;

    err = axfs_fill_region_data_ptrs(sb);
    if (err)
        goto out;

    /* Check that the root inode is in a sane state */
    if (!S_ISDIR(axfs_get_mode(sbi, 0))) {
        printk(KERN_ERR "axfs: root is not a directory\n");
        err = -EINVAL;
        goto out;
    }

    if (axfs_get_inode_num_entries(sbi, 0) == 0) {
        printk(KERN_INFO "axfs: empty filesystem\n");
        err = -EINVAL;
        goto out;
    }

    err = axfs_init_cblock_buffers(sbi);
    if (err)
        goto out;

    init_rwsem(&sbi->lock);

    return 0;

out:
    axfs_put_super(sb);
    return err;
}
Пример #7
0
void *axfs_get_physmem_addr(struct super_block *sb)
{
	struct axfs_super *sbi = AXFS_SB(sb);

	if (!sbi)
		return NULL;

	if (!axfs_is_physmem(sbi))
		return NULL;

	if(!axfs_virtaddr_is_valid(sbi))
		return NULL;

	return (void *)(sbi->virt_start_addr);
}
Пример #8
0
/* Read the last four bytes of the volume and make sure the AXFS magic is
   present. */
static int axfs_verify_eofs_magic(struct super_block *sb)
{
    struct axfs_super *sbi = AXFS_SB(sb);
    u32 eof_magic;
    u64 fsoffset = sbi->size - sizeof(eof_magic);

    if (axfs_copy_metadata(sb, &eof_magic, fsoffset, sizeof(eof_magic)))
        return -EINVAL;

    if (be32_to_cpu(eof_magic) == AXFS_MAGIC)
        return 0;

    printk(KERN_ERR "axfs: bad magic at end of image: got %x expected %x\n",
           be32_to_cpu(eof_magic), AXFS_MAGIC);
    return -EINVAL;
}
Пример #9
0
static int axfs_fill_region_descriptors(struct super_block *sb,
                                        struct axfs_super_onmedia *sbo)
{
    struct axfs_super *sbi = AXFS_SB(sb);
    struct axfs_region_desc_onmedia *out;

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
    out = kzalloc(sizeof(*out), GFP_KERNEL);
#else
    out = kmalloc(sizeof(*out), GFP_KERNEL);
#endif
    if (!out)
        return -ENOMEM;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13)
#else
    memset(out, 0, sizeof(*out));
#endif

    axfs_fill_region_desc(sb, out, sbo->strings, &sbi->strings);
    axfs_fill_region_desc(sb, out, sbo->xip, &sbi->xip);
    axfs_fill_region_desc(sb, out, sbo->compressed, &sbi->compressed);
    axfs_fill_region_desc(sb, out, sbo->byte_aligned, &sbi->byte_aligned);
    axfs_fill_region_desc(sb, out, sbo->node_type, &sbi->node_type);
    axfs_fill_region_desc(sb, out, sbo->node_index, &sbi->node_index);
    axfs_fill_region_desc(sb, out, sbo->cnode_offset, &sbi->cnode_offset);
    axfs_fill_region_desc(sb, out, sbo->cnode_index, &sbi->cnode_index);
    axfs_fill_region_desc(sb, out, sbo->banode_offset, &sbi->banode_offset);
    axfs_fill_region_desc(sb, out, sbo->cblock_offset, &sbi->cblock_offset);
    axfs_fill_region_desc(sb, out, sbo->inode_file_size,
                          &sbi->inode_file_size);
    axfs_fill_region_desc(sb, out, sbo->inode_name_offset,
                          &sbi->inode_name_offset);
    axfs_fill_region_desc(sb, out, sbo->inode_num_entries,
                          &sbi->inode_num_entries);
    axfs_fill_region_desc(sb, out, sbo->inode_mode_index,
                          &sbi->inode_mode_index);
    axfs_fill_region_desc(sb, out, sbo->inode_array_index,
                          &sbi->inode_array_index);
    axfs_fill_region_desc(sb, out, sbo->modes, &sbi->modes);
    axfs_fill_region_desc(sb, out, sbo->uids, &sbi->uids);
    axfs_fill_region_desc(sb, out, sbo->gids, &sbi->gids);

    kfree(out);

    return 0;
}
Пример #10
0
static int axfs_copy_metadata(struct super_block *sb, void *buf, u64 fsoffset,
                              u64 len)
{
    struct axfs_super *sbi = AXFS_SB(sb);
    u64 end = fsoffset + len;
    u64 a = sbi->mmap_size - fsoffset;
    u64 b = end - sbi->mmap_size;
    void *bb = (void *)((unsigned long)buf + (unsigned long)a);
    int err = 0;

    /* Catches case where sbi is not yet fully initialized. */
    if ((sbi->magic == 0) && (sbi->virt_start_addr != 0)) {
        axfs_copy_mem(sb, buf, fsoffset, len);
        return 0;
    }

    if (fsoffset < sbi->mmap_size) {
        if (end > sbi->mmap_size) {
            err = axfs_copy_metadata(sb, buf, fsoffset, a);
            if (err)
                return err;
            err = axfs_copy_metadata(sb, bb, sbi->mmap_size, b);
        } else {
            if (axfs_is_offset_mmapable(sbi, fsoffset))
                axfs_copy_mem(sb, buf, fsoffset, len);
            else if (axfs_has_bdev(sb))
                axfs_copy_block(sb, buf, fsoffset, len);
            else if (axfs_has_mtd(sb))
                err = axfs_copy_mtd(sb, buf, fsoffset, len);
        }
    } else {
        if (axfs_nodev(sb))
            axfs_copy_mem(sb, buf, fsoffset, len);
        else if (axfs_has_bdev(sb))
            axfs_copy_block(sb, buf, fsoffset, len);
        else if (axfs_has_mtd(sb))
            err = axfs_copy_mtd(sb, buf, fsoffset, len);
    }
    return err;
}
Пример #11
0
static int axfs_fixup_devices(struct super_block *sb)
{
    struct axfs_super *sbi = AXFS_SB(sb);
    int err = 0;

#ifndef NO_PHYSMEM
    if (axfs_is_physmem(sbi)) {
        axfs_map_physmem(sbi, sbi->mmap_size);
    } else if (axfs_has_mtd(sb)) {
#else
    if (axfs_has_mtd(sb)) {
#endif
        err = axfs_map_mtd(sb);
    } else if (axfs_is_iomem(sbi)) {
        sbi->phys_start_addr = 0;
    }

    if (!(axfs_virtaddr_is_valid(sbi)))
        sbi->mmap_size = 0;

    return err;
}

static void axfs_fill_region_desc(struct super_block *sb,
                                  struct axfs_region_desc_onmedia *out,
                                  __be64 offset_be, struct axfs_region_desc *in)
{
    u64 offset = be64_to_cpu(offset_be);

    axfs_copy_metadata(sb, (void *)out, offset, sizeof(*out));

    in->fsoffset = be64_to_cpu(out->fsoffset);
    in->size = be64_to_cpu(out->size);
    in->compressed_size = be64_to_cpu(out->compressed_size);
    in->max_index = be64_to_cpu(out->max_index);
    in->table_byte_depth = out->table_byte_depth;
    in->incore = out->incore;
}
Пример #12
0
u64 axfs_get_io_dev_size(struct super_block *sb)
{
    struct axfs_super *sbi = AXFS_SB(sb);
    return sbi->size - sbi->mmap_size;
}
Пример #13
0
static int axfs_fill_region_data_ptrs(struct super_block *sb)
{
    int err;
    struct axfs_super *sbi = AXFS_SB(sb);

    err = axfs_fill_region_data(sb, &sbi->strings, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->xip, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->compressed, false);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->byte_aligned, false);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->node_type, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->node_index, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->cnode_offset, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->cnode_index, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->banode_offset, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->cblock_offset, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->inode_file_size, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->inode_name_offset, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->inode_num_entries, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->inode_mode_index, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->inode_array_index, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->modes, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->uids, true);
    if (err)
        goto out;
    err = axfs_fill_region_data(sb, &sbi->gids, true);
    if (err)
        goto out;

out:
    return err;
}
Пример #14
0
static int axfs_fill_region_data(struct super_block *sb,
                                 struct axfs_region_desc *region, int force)
{
    struct axfs_super *sbi = AXFS_SB(sb);
    unsigned long addr;
    void *buff = NULL;
    void *vaddr;
    int err = -ENOMEM;
    u64 size = region->size;
    u64 fsoffset = region->fsoffset;
    u64 end = fsoffset + size;
    u64 c_size = region->compressed_size;

    if (size == 0)
        return 0;

    if (axfs_is_region_incore(region))
        goto incore;

    if (axfs_is_region_compressed(region))
        goto incore;

    if (axfs_is_region_xip(sbi, region)) {
        if ((end > sbi->mmap_size) && (force))
            goto incore;
        addr = sbi->virt_start_addr;
        addr += (unsigned long)fsoffset;
        region->virt_addr = (void *)addr;
        return 0;
    }

    if (force)
        goto incore;

    region->virt_addr = NULL;
    return 0;

incore:
    region->virt_addr = vmalloc(size);
    if (!region->virt_addr)
        goto out;
    vaddr = region->virt_addr;

    if (axfs_is_region_compressed(region)) {
        buff = vmalloc(c_size);
        if (!buff)
            goto out;
        axfs_copy_metadata(sb, buff, fsoffset, c_size);
        err = axfs_uncompress_block(vaddr, size, buff, c_size);
        if (!err)
            goto out;
        vfree(buff);
    } else {
        axfs_copy_metadata(sb, vaddr, fsoffset, size);
    }

    return 0;

out:
    vfree(buff);
    vfree(region->virt_addr);
    return err;
}
Пример #15
0
/******************************************************************************
 *
 * axfs_do_fill_data_ptrs
 *
 * Description:
 *      Fills the incore region descriptor with data from the onmedia version.
 *    Processes the region to populate virt_addr by mapping to the physical
 *    address or copying the data to RAM or if the data can be fetched later,
 *    it is set to NULL.
 *
 * Parameters:
 *    (IN) sb - pointer to the super block on media
 *
 *    (IN) region_desc_offset - offset to the region descriptor from the
 *                                beginning of filesystem
 *
 *    (OUT) iregion - pointer to the in RAM copy of the region descriptor
 *
 *    (IN) force_va - if true the region must have a valid virt_addr
 *
 * Returns:
 *    0 or error number
 *
 *****************************************************************************/
static int axfs_do_fill_data_ptrs(struct super_block *sb, u64 region_desc_offset, struct axfs_region_desc_incore *iregion, int force_va) {
	struct axfs_super_incore *sbi;
	struct axfs_region_desc_onmedia *oregion;
	unsigned long addr;
	void *mapped = NULL;
	int err;
	u64 size;
	u64 end;
	u64 struct_len = sizeof(*oregion);

	sbi = AXFS_SB(sb);

	oregion = (struct axfs_region_desc_onmedia *) axfs_fetch_data(sb,region_desc_offset,struct_len);

	iregion->fsoffset = be64_to_cpu(oregion->fsoffset);
	iregion->size = be64_to_cpu(oregion->size);
	iregion->compressed_size = be64_to_cpu(oregion->compressed_size);
	iregion->max_index = be64_to_cpu(oregion->max_index);
	iregion->table_byte_depth = oregion->table_byte_depth;
	iregion->incore = oregion->incore;
	vfree(oregion);

    if (iregion->size == 0)
		return 0;

	end = iregion->fsoffset + iregion->size;
	if( (AXFS_IS_REGION_XIP(sbi,iregion)) && !(force_va && (sbi->mmap_size < end)) ) {
		if(AXFS_PHYSADDR_IS_VALID(sbi) ) {
			addr = sbi->phys_start_addr;
			addr += (unsigned long)iregion->fsoffset;
			size = (sbi->mmap_size > (iregion->fsoffset + iregion->size)) ? iregion->size : (sbi->mmap_size - iregion->fsoffset);
			iregion->virt_addr = AXFS_REMAP(addr,size);
		} else {
			addr = sbi->virt_start_addr;
			addr += (unsigned long)iregion->fsoffset;
			iregion->virt_addr = (void *)addr;
		}
	} else if(AXFS_IS_REGION_INCORE(iregion) || AXFS_IS_REGION_COMPRESSED(iregion) || force_va) {
		iregion->virt_addr = vmalloc(iregion->size);
		if(!(iregion->virt_addr)) {
			err = -ENOMEM;
			goto out;
		}
		if(AXFS_IS_REGION_COMPRESSED(iregion)) {
			mapped = axfs_fetch_data(sb,iregion->fsoffset,iregion->compressed_size);
			err = axfs_uncompress_block(iregion->virt_addr,iregion->size,mapped,iregion->compressed_size);
			if (err)
				goto out;
		} else {
			mapped = axfs_fetch_data(sb,iregion->fsoffset,iregion->size);
			memcpy(iregion->virt_addr,mapped,iregion->size);
		}
	} else {
		iregion->virt_addr = NULL;
	}

	if(mapped)
		vfree(mapped);
	return 0;

out:
	if(mapped)
		vfree(mapped);
	if(iregion->virt_addr)
		vfree(iregion->virt_addr);
	return err;
}
Пример #16
0
/******************************************************************************
 *
 * axfs_do_fill_super
 *
 * Description:
 *      Uses the data collected by axfs_get_sb() and populates the superblock
 *
 * Parameters:
 *    (OUT) sb - pointer to the super block
 *
 *    (IN) fsi - pointer to the axfs_fill_super_info struct
 *
 * Returns:
 *    0 or error number
 *
 *****************************************************************************/
static int axfs_do_fill_super(struct super_block *sb, struct axfs_fill_super_info *fsi) {
	struct axfs_super_incore *sbi;
	struct axfs_super_onmedia *sbo;

#if 0
	u32 * pointer; /* REMOVEME */
	int i;
#endif
	sbo = fsi->onmedia_super_block;

	sbi = AXFS_SB(sb);

#if 0
	/* REMOVEME */
	printk("AXFS super block dump\n");
	pointer = (u32 *)sbo;
	for (i=0; i<128; i+=4)
	{
		printk("0x%06X: %08X %08X %08X %08X\n", (4*i), pointer[i], pointer[i+1], pointer[i+2], pointer[i+3]);
	}
#endif

	/* Do sanity checks on the superblock */
	if (be32_to_cpu(sbo->magic) != AXFS_MAGIC) {
		printk(KERN_ERR "axfs: wrong magic\n");
		goto out;
	}

	/* verify the signiture is correct */
	if (strncmp(sbo->signature, AXFS_SIGNATURE, sizeof(AXFS_SIGNATURE))) {
		printk(KERN_ERR "axfs: wrong axfs signature, read %s, expected %s\n", sbo->signature, AXFS_SIGNATURE);
		goto out;
	}

	sbi->magic = be32_to_cpu(sbo->magic);
	sbi->version_major = sbo->version_major;
	sbi->version_minor = sbo->version_minor;
	sbi->version_sub = sbo->version_sub;
	sbi->files = be64_to_cpu(sbo->files);
	sbi->size = be64_to_cpu(sbo->size);
	sbi->blocks = be64_to_cpu(sbo->blocks);
	sbi->mmap_size = be64_to_cpu(sbo->mmap_size);
	sbi->cblock_size = be32_to_cpu(sbo->cblock_size);

	if(fill_helper(sb, sbo->strings, sbi->strings, TRUE))
		goto out;
	if(fill_helper(sb, sbo->xip, sbi->xip, TRUE))
		goto out;
	if(fill_helper(sb, sbo->compressed, sbi->compressed, FALSE))
		goto out;
	if(fill_helper(sb, sbo->byte_aligned, sbi->byte_aligned, FALSE))
		goto out;
	if(fill_helper(sb, sbo->node_type, sbi->node_type, TRUE))
		goto out;
	if(fill_helper(sb, sbo->node_index, sbi->node_index, TRUE))
		goto out;
	if(fill_helper(sb, sbo->cnode_offset, sbi->cnode_offset, TRUE))
		goto out;
	if(fill_helper(sb, sbo->cnode_index, sbi->cnode_index, TRUE))
		goto out;
	if(fill_helper(sb, sbo->banode_offset, sbi->banode_offset, TRUE))
		goto out;
	if(fill_helper(sb, sbo->cblock_offset, sbi->cblock_offset, TRUE))
		goto out;
	if(fill_helper(sb, sbo->inode_file_size, sbi->inode_file_size, TRUE))
		goto out;
	if(fill_helper(sb, sbo->inode_name_offset, sbi->inode_name_offset, TRUE))
		goto out;
	if(fill_helper(sb, sbo->inode_num_entries, sbi->inode_num_entries, TRUE))
		goto out;
	if(fill_helper(sb, sbo->inode_mode_index, sbi->inode_mode_index, TRUE))
		goto out;
	if(fill_helper(sb, sbo->inode_array_index, sbi->inode_array_index, TRUE))
		goto out;
	if(fill_helper(sb, sbo->modes, sbi->modes, TRUE))
		goto out;
	if(fill_helper(sb, sbo->uids, sbi->uids, TRUE))
		goto out;
	if(fill_helper(sb, sbo->gids, sbi->gids, TRUE))
		goto out;

	axfs_fill_metadata_ptrs(sbi);

	init_rwsem(&sbi->lock); /* Semaphore for kernel premetion */

	return 0;

out:
	return -EINVAL;
}
Пример #17
0
static int axfs_get_onmedia_super(struct super_block *sb)
{
    int err;
    struct axfs_super *sbi = AXFS_SB(sb);
    struct axfs_super_onmedia *sbo;

    sbo = kmalloc(sizeof(*sbo), GFP_KERNEL);
    if (!sbo)
        return -ENOMEM;

#ifndef NO_PHYSMEM
    axfs_map_physmem(sbi, sizeof(*sbo));
#endif
    axfs_copy_metadata(sb, (void *)sbo, 0, sizeof(*sbo));

    /* Do sanity checks on the superblock */
    if (be32_to_cpu(sbo->magic) != AXFS_MAGIC) {
        printk(KERN_ERR "axfs: wrong magic: got %x, expected %x\n",
               be32_to_cpu(sbo->magic), AXFS_MAGIC);
        err = -EINVAL;
        goto out;
    }

    /* verify the signiture is correct */
    if (strncmp(sbo->signature, AXFS_SIGNATURE, sizeof(AXFS_SIGNATURE))) {
        printk(KERN_ERR "axfs: wrong signature: "
               "got '%s', expected '%s'\n",
               sbo->signature, AXFS_SIGNATURE);
        err = -EINVAL;
        goto out;
    }

    sbi->magic = be32_to_cpu(sbo->magic);
    sbi->version_major = sbo->version_major;
    sbi->version_minor = sbo->version_minor;
    sbi->version_sub = sbo->version_sub;
    sbi->files = be64_to_cpu(sbo->files);
    sbi->size = be64_to_cpu(sbo->size);
    sbi->blocks = be64_to_cpu(sbo->blocks);
    sbi->mmap_size = be64_to_cpu(sbo->mmap_size);
    sbi->cblock_size = be32_to_cpu(sbo->cblock_size);
    sbi->timestamp.tv_sec = be64_to_cpu(sbo->timestamp);
    sbi->timestamp.tv_nsec = 0;
    sbi->compression_type = sbo->compression_type;
    sbi->page_shift = sbo->page_shift;

    err = axfs_check_page_shift(sbi);
    if (err)
        goto out;

    err = axfs_check_compression_type(sbi);
    if (err)
        goto out;

    /* If no block or MTD device, adjust mmapable to cover all image */
    if (axfs_nodev(sb))
        sbi->mmap_size = sbi->size;

    err = axfs_fill_region_descriptors(sb, sbo);

out:
    kfree(sbo);
#ifndef NO_PHYSMEM
    axfs_unmap_physmem(axfs_get_physmem_addr(sb));
#endif
    return err;
}