/****************************************************************************** * * 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; }
/****************************************************************************** * * 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); }
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); }
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 }
/****************************************************************************** * * 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; }
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; }
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); }
/* 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; }
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; }
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; }
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; }
u64 axfs_get_io_dev_size(struct super_block *sb) { struct axfs_super *sbi = AXFS_SB(sb); return sbi->size - sbi->mmap_size; }
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; }
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; }
/****************************************************************************** * * 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; }
/****************************************************************************** * * 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; }
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; }