diff -Naur linux-2.6.26/fs/axfs/axfs_bdev.c linux-2.6.26-magellan/fs/axfs/axfs_bdev.c --- linux-2.6.26/fs/axfs/axfs_bdev.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/fs/axfs/axfs_bdev.c 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,207 @@ +/* + * Advanced XIP File System for Linux - AXFS + * Readonly, compressed, and XIP filesystem for Linux systems big and small + * + * Copyright(c) 2008 Numonyx + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * Authors: + * Jared Hulbert + * + * Project url: http://axfs.sourceforge.net + * + * axfs_bdev.c - + * Allows axfs to use block devices or has dummy functions if block + * device support is compiled out of the kernel. + * + */ + +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) +#else +#define CONFIG_BLOCK +#endif +#ifdef CONFIG_BLOCK +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#include +#include + + +int axfs_fill_super(struct super_block *sb, void *data, int silent); + +int axfs_get_sb_bdev(struct file_system_type *fs_type, int flags, + const char *dev_name, struct axfs_super *sbi, + struct vfsmount *mnt, int *err) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) + *err = get_sb_bdev(fs_type, flags, dev_name, sbi, axfs_fill_super, mnt); + + if (*err) + return FALSE; +#else + mnt->mnt_sb = + get_sb_bdev(fs_type, flags, dev_name, (void *)sbi, axfs_fill_super); + if (IS_ERR(mnt->mnt_sb)) { + *err = PTR_ERR(mnt->mnt_sb); + return FALSE; + } +#endif + return TRUE; +} + +void axfs_kill_block_super(struct super_block *sb) +{ + kill_block_super(sb); +} +#else +#include +#include +#define sector_t int + +int axfs_set_block_size(struct super_block *sb) +{ + int blocksize; + kdev_t dev = sb->s_dev; + + if (!(sb->s_bdev)) + return 0; + + blocksize = get_hardsect_size(dev); + if(blocksize < BLOCK_SIZE ) + blocksize = BLOCK_SIZE; + + if (set_blocksize(dev, blocksize) < 0) { + printk (KERN_ERR "axfs: unable to set secondary blocksize %d\n", blocksize); + return -EINVAL; + } + sb->s_blocksize = blocksize; + + return 0; +} +#endif + +/****************************************************************************** + * + * axfs_copy_block_data + * + * Description: Helper function to read data from block device + * + * Parameters: + * (IN) sb - pointer to super block structure. + * + * (IN) dst_addr - pointer to buffer into which data is to be read. + * + * (IN) boffset - offset within block device + * + * (IN) len - length of data to be read + * + * Returns: + * 0 or error number + * + *****************************************************************************/ +int axfs_copy_block(struct super_block *sb, void *dst_addr, u64 fsoffset, + u64 len) +{ + struct axfs_super *sbi = AXFS_SB(sb); + u64 boffset = AXFS_FSOFFSET_2_DEVOFFSET(sbi, fsoffset); + u64 blocks; + u64 blksize = sb->s_blocksize; + unsigned long dst; + unsigned long src; + sector_t block; + size_t bytes; + struct buffer_head *bh; + u64 copied = 0; + + if (len == 0) + return 0; + + blocks = len / blksize; + if ((len % blksize) > 0) + blocks += 1; + + while (copied < len) { + /* Explicit casting for ARM linker errors. */ + block = (sector_t) boffset + (sector_t) copied; + block /= (sector_t) blksize; + bh = sb_bread(sb, block); + src = (unsigned long)bh->b_data; + dst = (unsigned long)dst_addr; + if (copied == 0) { + /* Explicit casting for ARM linker errors. */ + bytes = (size_t) blksize; + bytes -= (size_t) boffset % (size_t) blksize; + if (bytes > len) + bytes = len; + /* Explicit casting for ARM linker errors. */ + src += (unsigned long)boffset % (unsigned long)blksize; + } else { + dst += copied; + if ((len - copied) < blksize) { + bytes = len - copied; + } else { + bytes = blksize; + } + } + memcpy((void *)dst, (void *)src, bytes); + copied += bytes; + brelse(bh); + } + return 0; +} + +int axfs_is_dev_bdev(char *path) +{ + struct nameidata nd; + int ret = FALSE; + + if (!path) + return FALSE; + + if (path_lookup(path, LOOKUP_FOLLOW, &nd)) + return FALSE; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) + if (S_ISBLK(nd.path.dentry->d_inode->i_mode)) +#else + if (S_ISBLK(nd.dentry->d_inode->i_mode)) +#endif + ret = TRUE; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) + path_put(&nd.path); +#else + path_release(&nd); +#endif + return ret; +} + +#else + +int axfs_get_sb_bdev(struct file_system_type *fs_type, int flags, + const char *dev_name, struct axfs_super *sbi, + struct vfsmount *mnt, int *err) +{ + return FALSE; +} + +void axfs_kill_block_super(struct super_block *sb) +{ +} + +int axfs_copy_block(struct super_block *sb, void *dst_addr, u64 fsoffset, + u64 len) +{ + return -EINVAL; +} + +int axfs_is_dev_bdev(char *path) +{ + return FALSE; +} + +#endif /* CONFIG_BLOCK */ diff -Naur linux-2.6.26/fs/axfs/axfs_inode.c linux-2.6.26-magellan/fs/axfs/axfs_inode.c --- linux-2.6.26/fs/axfs/axfs_inode.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/fs/axfs/axfs_inode.c 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,811 @@ +/* + * Advanced XIP File System for Linux - AXFS + * Readonly, compressed, and XIP filesystem for Linux systems big and small + * + * Copyright(c) 2008 Numonyx + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * Authors: + * Eric Anderson + * Jared Hulbert + * Sujaya Srinivasan + * Justin Treon + * + * Project url: http://axfs.sourceforge.net + * + * Borrowed heavily from fs/cramfs/inode.c by Linus Torvalds + * + * axfs_inode.c - + * Contains the most of the filesystem logic with the major exception of the + * mounting infrastructure. + * + */ + +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#else +#include +#endif + +/***************** functions in other axfs files ******************************/ +int axfs_get_sb(struct file_system_type *, int, const char *, void *, + struct vfsmount *); +void axfs_kill_super(struct super_block *); +void axfs_profiling_add(struct axfs_super *, unsigned long, unsigned int); +int axfs_copy_mtd(struct super_block *, void *, u64, u64); +int axfs_copy_block(struct super_block *, void *, u64, u64); +/******************************************************************************/ +static int axfs_readdir(struct file *, void *, filldir_t); +static int axfs_mmap(struct file *, struct vm_area_struct *); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static ssize_t axfs_file_read(struct file *, char __user *, size_t, loff_t *); +static struct dentry *axfs_lookup(struct inode *, struct dentry *, + struct nameidata *); +static int axfs_get_xip_mem(struct address_space *, pgoff_t, int, void **, + unsigned long *); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) +static int axfs_fault(struct vm_area_struct *, struct vm_fault *); +#else +static struct page *axfs_nopage(struct vm_area_struct *, unsigned long, int *); +#endif +#else +static ssize_t axfs_file_read(struct file *, char *, size_t, loff_t *); +static struct dentry *axfs_lookup(struct inode *, struct dentry *); +static int axfs_get_xip_mem(struct address_space *, unsigned long, int, void **, + unsigned long *); +static struct page *axfs_nopage(struct vm_area_struct *, unsigned long, int); +#endif +static int axfs_readpage(struct file *, struct page *); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) +struct page *axfs_get_xip_page(struct address_space *mapping, sector_t offset, + int create); +#endif +#endif + +/******************************************************************************/ + +static struct file_operations axfs_directory_operations = { + .llseek = generic_file_llseek, + .read = generic_read_dir, + .readdir = axfs_readdir, +}; + +static struct file_operations axfs_fops = { + .read = axfs_file_read, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + .aio_read = generic_file_aio_read, +#endif + .mmap = axfs_mmap, +}; + +static struct address_space_operations axfs_aops = { + .readpage = axfs_readpage, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) + .get_xip_mem = axfs_get_xip_mem, +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) + .get_xip_page = axfs_get_xip_page, +#endif +#endif +}; + +static struct inode_operations axfs_dir_inode_operations = { + .lookup = axfs_lookup, +}; + +static struct vm_operations_struct axfs_vm_ops = { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) + .fault = axfs_fault, +#else + .nopage = axfs_nopage, +#endif +}; + +static int axfs_copy_data(struct super_block *sb, void *dst, + struct axfs_region_desc *region, u64 offset, u64 len) +{ + u64 mmapped = 0; + u64 end = region->fsoffset + offset + len; + u64 begin = region->fsoffset + offset; + u64 left; + void *addr; + void *newdst; + struct axfs_super *sbi = AXFS_SB(sb); + + if (len == 0) + return 0; + + if (region->virt_addr) { + if (sbi->mmap_size >= end) { + mmapped = len; + } else if (sbi->mmap_size > begin) { + mmapped = sbi->mmap_size - begin; + } + } + + if (mmapped) { + addr = (void *)(region->virt_addr + offset); + memcpy(dst, addr, mmapped); + } + + newdst = (void *)(dst + mmapped); + left = len - mmapped; + + if (left == 0) + return len; + + if (AXFS_HAS_BDEV(sb)) { + return axfs_copy_block(sb, newdst, begin + mmapped, left); + } else if (AXFS_HAS_MTD(sb)) { + return axfs_copy_mtd(sb, newdst, begin + mmapped, left); + } else { + return 0; + } +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static int axfs_iget5_test(struct inode *inode, void *opaque) +{ + u64 *inode_number = (u64 *) opaque; + + if (inode->i_sb == NULL) { + printk(KERN_ERR "axfs_iget5_test:" + " the super block is set to null\n"); + } + if (inode->i_ino == *inode_number) + return 1; /* matches */ + else + return 0; /* does not match */ +} + +static int axfs_iget5_set(struct inode *inode, void *opaque) +{ + u64 *inode_number = (u64 *) opaque; + + if (inode->i_sb == NULL) { + printk(KERN_ERR "axfs_iget5_set:" + " the super block is set to null \n"); + } + inode->i_ino = *inode_number; + return 0; +} +#endif + +struct inode *axfs_create_vfs_inode(struct super_block *sb, int ino) +{ + struct axfs_super *sbi = AXFS_SB(sb); + struct inode *inode; + u64 size; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + inode = iget5_locked(sb, ino, axfs_iget5_test, axfs_iget5_set, &ino); + + if (!(inode && (inode->i_state & I_NEW))) +#else + inode = new_inode(sb); + + if (!inode) +#endif + return inode; + + inode->i_mode = AXFS_GET_MODE(sbi, ino); + inode->i_uid = AXFS_GET_UID(sbi, ino); + size = AXFS_GET_INODE_FILE_SIZE(sbi, ino); + inode->i_size = size; + inode->i_blocks = AXFS_GET_INODE_NUM_ENTRIES(sbi, ino); + inode->i_blkbits = PAGE_CACHE_SIZE * 8; + inode->i_gid = AXFS_GET_GID(sbi, ino); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + inode->i_mtime = inode->i_atime = inode->i_ctime = sbi->timestamp; +#else + inode->i_mtime = inode->i_atime = inode->i_ctime = sbi->timestamp.tv_sec; +#endif + inode->i_ino = ino; + + if (S_ISREG(inode->i_mode)) { + inode->i_fop = &axfs_fops; + inode->i_data.a_ops = &axfs_aops; + inode->i_mapping->a_ops = &axfs_aops; + } else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &axfs_dir_inode_operations; + inode->i_fop = &axfs_directory_operations; + } else if (S_ISLNK(inode->i_mode)) { + inode->i_op = &page_symlink_inode_operations; + inode->i_data.a_ops = &axfs_aops; + } else { + inode->i_size = 0; + inode->i_blocks = 0; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + init_special_inode(inode, inode->i_mode, old_decode_dev(size)); + } + unlock_new_inode(inode); +#else + init_special_inode(inode, inode->i_mode, to_kdev_t(size)); + } +#endif + + return inode; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) +#else +static int axfs_insert_pfns(struct file *file, struct vm_area_struct *vma) +{ + struct inode *inode = file->f_dentry->d_inode; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct address_space *mapping = file->f_mapping; +#else + struct address_space *mapping = inode->i_mapping; +#endif + struct super_block *sb = inode->i_sb; + struct axfs_super *sbi = AXFS_SB(sb); + unsigned long array_index, length, offset, count, addr, pfn; + void *kaddr; + unsigned int numpages; + u64 ino_number = inode->i_ino; + int error; + + offset = vma->vm_pgoff; + + array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number); + array_index += offset; + length = vma->vm_end - vma->vm_start; + + if (length > inode->i_size) + length = inode->i_size; + + length = PAGE_ALIGN(length); + numpages = length >> PAGE_SHIFT; + + for (count = 0; count < numpages; count++, array_index++) { + if (!AXFS_IS_NODE_XIP(sbi, array_index)) + continue; +#ifdef VM_XIP + vma->vm_flags |= (VM_IO | VM_XIP); +#endif +#ifdef VM_MIXEDMAP + vma->vm_flags |= (VM_IO | VM_MIXEDMAP); +#endif + addr = vma->vm_start + (PAGE_SIZE * count); + + axfs_get_xip_mem(mapping, offset + count, 0, &kaddr, &pfn); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) + error = vm_insert_pfn(vma, addr, pfn); +#else + error = + remap_pfn_range(vma, addr, pfn, PAGE_SIZE, + vma->vm_page_prot); +#endif +#else + error = + remap_page_range(addr, pfn << PAGE_SHIFT, PAGE_SIZE, + vma->vm_page_prot); +#endif + if (error) + return error; + } + + return 0; +} +#endif + +static int axfs_mmap(struct file *file, struct vm_area_struct *vma) +{ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + file_accessed(file); +#endif + + vma->vm_ops = &axfs_vm_ops; + +#ifdef VM_MIXEDMAP +#ifdef VM_CAN_NONLINEAR + vma->vm_flags |= VM_CAN_NONLINEAR | VM_MIXEDMAP; +#else + vma->vm_flags |= VM_IO | VM_MIXEDMAP; +#endif +#else +#ifdef VM_PFNMAP + vma->vm_flags |= VM_IO | VM_PFNMAP; +#else + vma->vm_flags |= VM_IO; +#endif +#endif +#ifdef VM_XIP + vma->vm_flags |= VM_XIP; +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) + return 0; +#else + return axfs_insert_pfns(file, vma); +#endif +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static struct dentry *axfs_lookup(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) +#else +static struct dentry *axfs_lookup(struct inode *dir, struct dentry *dentry) +#endif +{ + struct super_block *sb = dir->i_sb; + struct axfs_super *sbi = AXFS_SB(sb); + u64 ino_number = dir->i_ino; + u64 dir_index = 0; + u64 entry; + char *name; + int namelen, err; + + while (dir_index < AXFS_GET_INODE_NUM_ENTRIES(sbi, ino_number)) { + entry = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number); + entry += dir_index; + + name = AXFS_GET_INODE_NAME(sbi, entry); + namelen = strlen(name); + + /* fast test, the entries are sorted alphabetically and the + * first letter is smaller than the first letter in the search + * name then it isn't in this directory. Keeps this loop from + * needing to scan through always. + */ + if (dentry->d_name.name[0] < name[0]) + break; + + dir_index++; + + /* Quick check that the name is roughly the right length */ + if (dentry->d_name.len != namelen) + continue; + + err = memcmp(dentry->d_name.name, name, namelen); + if (err > 0) + continue; + + /* The file name isn't present in the directory. */ + if (err < 0) + break; + + d_add(dentry, axfs_create_vfs_inode(dir->i_sb, entry)); + goto out; + + } + d_add(dentry, NULL); + +out: + return NULL; +} + +static int axfs_readdir(struct file *filp, void *dirent, filldir_t filldir) +{ + struct inode *inode = filp->f_dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct axfs_super *sbi = AXFS_SB(sb); + u64 ino_number = inode->i_ino; + u64 entry; + loff_t dir_index; + char *name; + int namelen, mode; + int err = 0; + + /* Get the current index into the directory and verify it is not beyond + the end of the list */ + dir_index = filp->f_pos; + if (dir_index >= AXFS_GET_INODE_NUM_ENTRIES(sbi, ino_number)) + goto out; + + /* Verify the inode is for a directory */ + if (!(S_ISDIR(inode->i_mode))) { + err = -EINVAL; + goto out; + } + + while (dir_index < AXFS_GET_INODE_NUM_ENTRIES(sbi, ino_number)) { + entry = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number) + dir_index; + + name = (char *)AXFS_GET_INODE_NAME(sbi, entry); + namelen = strlen(name); + + mode = (int)AXFS_GET_MODE(sbi, entry); + err = filldir(dirent, name, namelen, dir_index, entry, mode); + + if (err) + break; + + dir_index++; + filp->f_pos = dir_index; + } + +out: + return 0; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) +/****************************************************************************** + * + * axfs_fault + * + * Description: This function is mapped into the VMA operations vector, and + * gets called on a page fault. Depending on whether the page + * is XIP or compressed, xip_file_fault or filemap_fault is + * called. This function also logs when a fault occurs when + * profiling is on. + * + * Parameters: + * (IN) vma - The virtual memory area corresponding to a file + * + * (IN) vmf - The fault info pass in by the fault handler + * + * Returns: + * 0 or error number + * + *****************************************************************************/ +static int axfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +#else +static struct page *axfs_nopage(struct vm_area_struct *vma, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + unsigned long address, int *type) +#else + unsigned long address, int type) +#endif +#endif +{ + struct file *file = vma->vm_file; + struct inode *inode = file->f_dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct axfs_super *sbi = AXFS_SB(sb); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) +#else + unsigned long pgoff; +#endif + u64 ino_number = inode->i_ino; + u64 array_index; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) + array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number) + vmf->pgoff; +#else + pgoff = ((address - vma->vm_start) >> PAGE_CACHE_SHIFT) + vma->vm_pgoff; + array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number) + pgoff; +#endif + + /* if that pages are marked for write they will probably end up in RAM + therefore we don't want their counts for being XIP'd */ + if (!(vma->vm_flags & VM_WRITE)) + axfs_profiling_add(sbi, array_index, ino_number); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) + /* figure out if the node is XIP or compressed and call the + appropriate function + */ +#ifdef VM_MIXEDMAP + if (AXFS_IS_NODE_XIP(sbi, array_index)) +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) + if (AXFS_IS_NODE_XIP(sbi, array_index) && !AXFS_PHYSADDR_IS_VALID(sbi)) +#else + if (!(AXFS_IS_POINTED(sbi) && !AXFS_PHYSADDR_IS_VALID(sbi))) +#endif +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) + return xip_file_fault(vma, vmf); +#else + return xip_file_nopage(vma, address, type); +#endif +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) + return filemap_fault(vma, vmf); +#else + return filemap_nopage(vma, address, type); +#endif +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static ssize_t axfs_xip_file_read(struct file *file, char __user *buf, +#else +static ssize_t axfs_xip_file_read(struct file *file, char *buf, +#endif + size_t len, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct address_space *mapping = file->f_mapping; +#else + struct address_space *mapping = inode->i_mapping; +#endif + unsigned long index, end_index, offset; + loff_t isize, pos; + size_t copied = 0, error = 0; + + pos = *ppos; + index = pos >> PAGE_CACHE_SHIFT; + offset = pos & ~PAGE_CACHE_MASK; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + isize = i_size_read(inode); +#else + isize = inode->i_size; +#endif + if (!isize) + goto out; + + end_index = (isize - 1) >> PAGE_CACHE_SHIFT; + do { + unsigned long nr, left, pfn; + void *xip_mem; + int zero = 0; + + /* nr is the maximum number of bytes to copy from this page */ + nr = PAGE_CACHE_SIZE; + if (index >= end_index) { + if (index > end_index) + goto out; + nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1; + if (nr <= offset) + goto out; + } + nr = nr - offset; + if (nr > len) + nr = len; + axfs_get_xip_mem(mapping, index, 0, &xip_mem, &pfn); + if (!xip_mem) { + error = -EIO; + goto out; + } + if (unlikely(IS_ERR(xip_mem))) { + if (PTR_ERR(xip_mem) == -ENODATA) { + /* sparse */ + zero = 1; + } else { + error = PTR_ERR(xip_mem); + goto out; + } + } + /* + * Ok, we have the mem, so now we can copy it to user space... + * + * The actor routine returns how many bytes were actually used.. + * NOTE! This may not be the same as how much of a user buffer + * we filled up (we may be padding etc), so we can only update + * "pos" here (the actor routine has to update the user buffer + * pointers and the remaining count). + */ + if (!zero) + left = + __copy_to_user(buf + copied, xip_mem + offset, nr); + else + left = __clear_user(buf + copied, nr); + + if (left) { + error = -EFAULT; + goto out; + } + + copied += (nr - left); + offset += (nr - left); + index += offset >> PAGE_CACHE_SHIFT; + offset &= ~PAGE_CACHE_MASK; + } while (copied < len); + +out: + *ppos = pos + copied; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + if (file) + file_accessed(file); +#endif + + return (copied ? copied : error); +} +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +/****************************************************************************** + * + * axfs_file_read + * + * Description: axfs_file_read is mapped into the file_operations vector for + * all axfs files. It loops through the pages to be read and calls + * either do_sync_read (if the page is a compressed one) or + * xip_file_read (if the page is XIP). + * + * Parameters: + * (IN) filp - file to be read + * + * (OUT) buf - user buffer that is filled with the data that we read. + * + * (IN) len - length of file to be read + * + * (IN) ppos - offset within the file to read from + * + * Returns: + * actual size of data read. + * + *****************************************************************************/ +static ssize_t axfs_file_read(struct file *filp, char __user *buf, size_t len, + loff_t *ppos) +#else +static ssize_t axfs_file_read(struct file *filp, char * buf, size_t len, + loff_t * ppos) +#endif +{ + struct inode *inode = filp->f_dentry->d_inode; + struct super_block *sb = inode->i_sb; + struct axfs_super *sbi = AXFS_SB(sb); + size_t read = 0, total_read = 0; + size_t readlength, actual_size, file_size, remaining; + u64 ino_number = inode->i_ino; + u64 size, array_index; + + file_size = AXFS_GET_INODE_FILE_SIZE(sbi, ino_number); + remaining = file_size - *ppos; + actual_size = len > remaining ? remaining : len; + readlength = actual_size < PAGE_SIZE ? actual_size : PAGE_SIZE; + + for (size = actual_size; size > 0; size -= read) { + array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number); + array_index += *ppos >> PAGE_SHIFT; + + if (AXFS_IS_NODE_XIP(sbi, array_index)) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) + read = xip_file_read(filp, buf, readlength, ppos); +#else + read = axfs_xip_file_read(filp, buf, readlength, ppos); +#endif + } else { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + read = do_sync_read(filp, buf, readlength, ppos); +#else + read = generic_file_read(filp, buf, readlength, ppos); +#endif + + } + buf += read; + total_read += read; + + if ((len - total_read < PAGE_SIZE) && (total_read != len)) + readlength = len - total_read; + } + + return total_read; +} + +static int axfs_readpage(struct file *file, struct page *page) +{ + struct inode *inode = page->mapping->host; + struct super_block *sb = inode->i_sb; + struct axfs_super *sbi = AXFS_SB(sb); + u64 array_index, node_index, cnode_index, maxblock, ofs; + u64 ino_number = inode->i_ino; + u32 max_len, cnode_offset; + u32 cblk_size = sbi->cblock_size; + u32 len = 0; + u8 node_type; + void *pgdata; + void *src; + void *cblk0 = sbi->cblock_buffer[0]; + void *cblk1 = sbi->cblock_buffer[1]; + + maxblock = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; + pgdata = kmap(page); + + if (page->index >= maxblock) + goto out; + + array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number); + array_index += page->index; + + node_index = AXFS_GET_NODE_INDEX(sbi, array_index); + node_type = AXFS_GET_NODE_TYPE(sbi, array_index); + + if (node_type == Compressed) { + /* node is in compessed region */ + cnode_offset = AXFS_GET_CNODE_OFFSET(sbi, node_index); + cnode_index = AXFS_GET_CNODE_INDEX(sbi, node_index); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#else +retry: +#endif + down_write(&sbi->lock); + if (cnode_index != sbi->current_cnode_index) { + /* uncompress only necessary if different cblock */ + ofs = AXFS_GET_CBLOCK_OFFSET(sbi, cnode_index); + len = AXFS_GET_CBLOCK_OFFSET(sbi, cnode_index + 1); + len -= ofs; + axfs_copy_data(sb, cblk1, &(sbi->compressed), ofs, len); + axfs_uncompress_block(cblk0, cblk_size, cblk1, len); + sbi->current_cnode_index = cnode_index; + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + downgrade_write(&sbi->lock); +#else + up_write(&sbi->lock); + down_read(&sbi->lock); + if(cnode_index != sbi->current_cnode_index){ + up_read(&sbi->lock); + goto retry; + } +#endif + max_len = cblk_size - cnode_offset; + len = max_len > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : max_len; + src = (void *)((unsigned long)cblk0 + cnode_offset); + memcpy(pgdata, src, len); + up_read(&sbi->lock); + } else if (node_type == Byte_Aligned) { + /* node is in BA region */ + ofs = AXFS_GET_BANODE_OFFSET(sbi, node_index); + max_len = sbi->byte_aligned.size - ofs; + len = max_len > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE : max_len; + axfs_copy_data(sb, pgdata, &(sbi->byte_aligned), ofs, len); + } else { + /* node is XIP */ + ofs = node_index << PAGE_SHIFT; + len = PAGE_CACHE_SIZE; + axfs_copy_data(sb, pgdata, &(sbi->xip), ofs, len); + } + +out: + memset(pgdata + len, 0, PAGE_CACHE_SIZE - len); + kunmap(page); + flush_dcache_page(page); + SetPageUptodate(page); + unlock_page(page); + return 0; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static int axfs_get_xip_mem(struct address_space *mapping, pgoff_t offset, +#else +static int axfs_get_xip_mem(struct address_space *mapping, unsigned long offset, +#endif + int create, void **kaddr, unsigned long *pfn) +{ + struct inode *inode = mapping->host; + struct super_block *sb = inode->i_sb; + struct axfs_super *sbi = AXFS_SB(sb); + u64 ino_number = inode->i_ino; + u64 ino_index, node_index; + + ino_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number); + ino_index += offset; + + node_index = AXFS_GET_NODE_INDEX(sbi, ino_index); + + *kaddr = (void *)(sbi->xip.virt_addr + (node_index << PAGE_SHIFT)); + if (AXFS_PHYSADDR_IS_VALID(sbi)) { + *pfn = (AXFS_GET_XIP_REGION_PHYSADDR(sbi) >> PAGE_SHIFT); + *pfn += node_index; + } else { + *pfn = page_to_pfn(virt_to_page((unsigned long)*kaddr)); + } + + return 0; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,12) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) +#else +struct page *axfs_get_xip_page(struct address_space *mapping, sector_t offset, + int create) +{ + unsigned long pfn; + void *kaddr; + pgoff_t pgoff; + + pgoff = (offset * 512) >> PAGE_SHIFT; + + axfs_get_xip_mem(mapping, pgoff, create, &kaddr, &pfn); + + return virt_to_page(kaddr); +} + +#endif +#endif diff -Naur linux-2.6.26/fs/axfs/axfs_mtd.c linux-2.6.26-magellan/fs/axfs/axfs_mtd.c --- linux-2.6.26/fs/axfs/axfs_mtd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/fs/axfs/axfs_mtd.c 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,522 @@ +/* + * Advanced XIP File System for Linux - AXFS + * Readonly, compressed, and XIP filesystem for Linux systems big and small + * + * Copyright(c) 2008 Numonyx + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * Authors: + * Jared Hulbert + * + * Project url: http://axfs.sourceforge.net + * + * axfs_mtd.c - + * Allows axfs to use mtd devices or has dummy functions if mtd + * device support is compiled out of the kernel. + */ + +#include +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#include + +#ifdef CONFIG_MTD +#define AXFS_CONFIG_MTD +#endif +#else +#endif + +#ifdef AXFS_CONFIG_MTD +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) +#include +#else +#include +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) +#else +#define OLD_POINT 1 +#endif + +int axfs_fill_super(struct super_block *, void *, int); + +static struct mtd_info *axfs_get_mtd_device(int mtdnr) +{ + struct mtd_info *device; + + device = get_mtd_device(NULL, mtdnr); + + if (!PTR_ERR(device)) + return NULL; + + return device; +} + +int axfs_is_dev_mtd(char *path, int *mtdnr) +{ + char *off = NULL; + char *endptr = NULL; + char dev[] = "/dev/\0"; + char mtd[] = "mtd\0"; + char mtdblk[] = "mtdblock\0"; + + if (!path || !*path) + return FALSE; + + off = path; + + if (strncmp(dev, off, strlen(dev)) == 0) + off += strlen(dev); + + if (!strncmp(mtd, off, strlen(mtd)) && isdigit(off[strlen(mtd)])) + off += strlen(mtd); + + if (!strncmp(mtdblk, off, strlen(mtdblk)) + && isdigit(off[strlen(mtdblk)])) + off += strlen(mtdblk); + + *mtdnr = simple_strtoul(off, &endptr, 0); + + if (!*endptr) + return TRUE; + + return FALSE; +} + +static struct mtd_info *axfs_get_mtd_info(struct super_block *sb, u64 fsoffset) +{ + struct axfs_super *sbi = AXFS_SB(sb); + + if (fsoffset == 0) + return (struct mtd_info *)AXFS_MTD0(sb); + + if (fsoffset < sbi->mmap_size) + return (struct mtd_info *)AXFS_MTD0(sb); + + if (AXFS_MTD1(sb) != NULL) + return (struct mtd_info *)AXFS_MTD1(sb); + + return (struct mtd_info *)AXFS_MTD0(sb); +} + +int axfs_copy_mtd(struct super_block *sb, void *dst, u64 fsoffset, u64 len) +{ + struct axfs_super *sbi = AXFS_SB(sb); + u64 offset = AXFS_FSOFFSET_2_DEVOFFSET(sbi, fsoffset); + struct mtd_info *mtd; + u_char *mtdbuf = (u_char *) dst; + size_t retlen; + int err; + + if (len == 0) + return 0; + + mtd = axfs_get_mtd_info(sb, fsoffset); + err = mtd->read(mtd, (loff_t) offset, (size_t) len, &retlen, mtdbuf); + + if (len != retlen) + return -EIO; + + return err; +} + +/****************************************************************************** + * + * axfs_map_mtd + * + * Description: When provided, uses the mtd point() capability to map allow + * axfs a direct memory access to the filesystem. + * + * Parameters: + * (IN) sb - pointer to the super_block structure + * + * Returns: + * 0 or error number + * + *****************************************************************************/ +int axfs_map_mtd(struct super_block *sb) +{ + struct axfs_super *sbi = AXFS_SB(sb); + struct mtd_info *mtd = (struct mtd_info *)AXFS_MTD0(sb); + size_t retlen; + int err = 0; +#ifndef OLD_POINT + void *virt; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) + resource_size_t phys; +#else + unsigned long phys; +#endif +#else + u_char *virt; +#endif + + printk(KERN_ERR "axfs_map_mtd\n"); + + if (!mtd->point || !mtd->unpoint) + return 0; + +#ifndef OLD_POINT + err = mtd->point(mtd, 0, sbi->mmap_size, &retlen, &virt, &phys); +#else + err = mtd->point(mtd, 0, sbi->mmap_size, &retlen, &virt); +#endif + if (err) + return err; + + if (retlen != sbi->mmap_size) { +#ifndef OLD_POINT + mtd->unpoint(mtd, 0, retlen); +#else + mtd->unpoint(mtd, 0, 0, retlen); +#endif + return -EINVAL; + } + + sbi->virt_start_addr = (unsigned long)virt; +#ifndef OLD_POINT + sbi->phys_start_addr = (unsigned long)phys; +#else + sbi->phys_start_addr = 0; +#endif + sbi->mtd_pointed = TRUE; + + return 0; +} + +void axfs_unmap_mtd(struct super_block *sb) +{ + struct axfs_super *sbi = AXFS_SB(sb); + struct mtd_info *mtd = (struct mtd_info *)AXFS_MTD0(sb); + + if (!sbi) + return; + + if (AXFS_MTD1(sb)) + put_mtd_device((struct mtd_info *)AXFS_MTD1(sb)); + + if (AXFS_IS_POINTED(sbi)) { +#ifndef OLD_POINT + mtd->unpoint(mtd, 0, sbi->mmap_size); +#else + mtd->unpoint(mtd, 0, 0, sbi->mmap_size); +#endif + } else { + if (AXFS_MTD0(sb)) + put_mtd_device((struct mtd_info *)AXFS_MTD0(sb)); + } +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) +#else +/* -------------------- START COPY FROM 2.6.22 -------------------------- */ +/* MTD-based superblock management + * + * Copyright © 2001-2007 Red Hat, Inc. All Rights Reserved. + * Written by: David Howells + * David Woodhouse + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +/* + * compare superblocks to see if they're equivalent + * - they are if the underlying MTD device is the same + */ +static int get_sb_mtd_compare(struct super_block *sb, void *_mtd) +{ + struct mtd_info *mtd = _mtd; + struct mtd_info *s_mtd = (struct mtd_info *)AXFS_MTD0(sb); + + if (s_mtd == mtd) { + DEBUG(2, "MTDSB: Match on device %d (\"%s\")\n", + mtd->index, mtd->name); + return 1; + } + + DEBUG(2, "MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", + s_mtd->index, s_mtd->name, mtd->index, mtd->name); + return 0; +} + +/* + * mark the superblock by the MTD device it is using + * - set the device number to be the correct MTD block device for pesuperstence + * of NFS exports + */ +static int get_sb_mtd_set(struct super_block *sb, void *_mtd) +{ + struct mtd_info *mtd = _mtd; + struct mtd_info *s_mtd = (struct mtd_info *)AXFS_MTD0(sb); + + s_mtd = mtd; + sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, mtd->index); + return 0; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) +#else +/* Lifted wholesale from 2.6.22 */ +int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) +{ + mnt->mnt_sb = sb; + mnt->mnt_root = dget(sb->s_root); + return 0; +} +#endif +/* + * get a superblock on an MTD-backed filesystem + */ +static int get_sb_mtd_aux(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + struct mtd_info *mtd, + int (*fill_super) (struct super_block *, void *, int), + struct vfsmount *mnt) +{ + struct super_block *sb; + int ret; + + sb = sget(fs_type, get_sb_mtd_compare, get_sb_mtd_set, mtd); + if (IS_ERR(sb)) + goto out_error; + + if (sb->s_root) + goto already_mounted; + + /* fresh new superblock */ + DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n", + mtd->index, mtd->name); + + ret = fill_super(sb, data, 0); + if (ret < 0) { + up_write(&sb->s_umount); + deactivate_super(sb); + return ret; + } + + /* go */ + sb->s_flags |= MS_ACTIVE; + return simple_set_mnt(mnt, sb); + + /* new mountpoint for an already mounted superblock */ + already_mounted: + DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n", + mtd->index, mtd->name); + ret = simple_set_mnt(mnt, sb); + goto out_put; + + out_error: + ret = PTR_ERR(sb); + out_put: + put_mtd_device(mtd); + return ret; +} + +/* + * get a superblock on an MTD-backed filesystem by MTD device number + */ +static int get_sb_mtd_nr(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, int mtdnr, + int (*fill_super) (struct super_block *, void *, int), + struct vfsmount *mnt) +{ + struct mtd_info *mtd; + + mtd = get_mtd_device(NULL, mtdnr); + if (IS_ERR(mtd)) { + DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr); + return PTR_ERR(mtd); + } + + return get_sb_mtd_aux(fs_type, flags, dev_name, data, mtd, fill_super, + mnt); +} + +/* + * set up an MTD-based superblock + */ +static int get_sb_mtd(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, + int (*fill_super) (struct super_block *, void *, int), + struct vfsmount *mnt) +{ + struct nameidata nd; + int mtdnr, ret; + + if (!dev_name) + return -EINVAL; + + DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name); + + /* the preferred way of mounting in future; especially when + * CONFIG_BLOCK=n - we specify the underlying MTD device by number or + * by name, so that we don't require block device support to be present + * in the kernel. */ + if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { + if (dev_name[3] == ':') { + struct mtd_info *mtd; + + /* mount by MTD device name */ + DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"\n", dev_name + 4); + + for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { + mtd = get_mtd_device(NULL, mtdnr); + if (!IS_ERR(mtd)) { + if (!strcmp(mtd->name, dev_name + 4)) + return get_sb_mtd_aux(fs_type, + flags, + dev_name, + data, mtd, + fill_super, + mnt); + + put_mtd_device(mtd); + } + } + + printk(KERN_NOTICE "MTD:" + " MTD device with name \"%s\" not found.\n", + dev_name + 4); + + } else if (isdigit(dev_name[3])) { + /* mount by MTD device number name */ + char *endptr; + + mtdnr = simple_strtoul(dev_name + 3, &endptr, 0); + if (!*endptr) { + /* It was a valid number */ + DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n", mtdnr); + return get_sb_mtd_nr(fs_type, flags, + dev_name, data, + mtdnr, fill_super, mnt); + } + } + } + + /* try the old way - the hack where we allowed users to mount + * /dev/mtdblock$(n) but didn't actually _use_ the blockdev + */ + ret = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); + + DEBUG(1, "MTDSB: path_lookup() returned %d, inode %p\n", + ret, nd.dentry ? nd.dentry->d_inode : NULL); + + if (ret) + return ret; + + ret = -EINVAL; + + if (!S_ISBLK(nd.dentry->d_inode->i_mode)) + goto out; + + if (nd.mnt->mnt_flags & MNT_NODEV) { + ret = -EACCES; + goto out; + } + + if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) + goto not_an_MTD_device; + + mtdnr = iminor(nd.dentry->d_inode); + path_release(&nd); + + return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, + mnt); + + not_an_MTD_device: + printk(KERN_NOTICE + "MTD: Attempt to mount non-MTD device \"%s\"\n", dev_name); + out: + path_release(&nd); + return ret; + +} + +/* + * destroy an MTD-based superblock + */ +static void kill_mtd_super(struct super_block *sb) +{ + struct mtd_info *s_mtd = (struct mtd_info *)AXFS_MTD0(sb); + struct axfs_super *sbi = AXFS_SB(sb); + generic_shutdown_super(sb); + put_mtd_device(s_mtd); + sbi->mtd0 = NULL; +} + +/* ---------------------- END COPY --------------------------------------*/ +#endif + +int axfs_get_sb_mtd(struct file_system_type *fs_type, int flags, + const char *dev_name, struct axfs_super *sbi, + struct vfsmount *mnt, int *err) +{ + int nflags, mtdnr; + + if (axfs_is_dev_mtd(sbi->second_dev, &mtdnr)) { + sbi->mtd1 = (void *)axfs_get_mtd_device(mtdnr); + if (!sbi->mtd1) { + *err = -EINVAL; + return FALSE; + } + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) + nflags = flags & MS_SILENT; +#else + nflags = flags; +#endif + + *err = get_sb_mtd(fs_type, nflags, dev_name, sbi, axfs_fill_super, mnt); + if (*err) + return FALSE; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) + sbi->mtd0 = mnt->mnt_sb->s_mtd; +#endif + return TRUE; +} + +void axfs_kill_mtd_super(struct super_block *sb) +{ + kill_mtd_super(sb); +} +#else + +int axfs_map_mtd(struct super_block *sb) +{ + return 0; +} + +void axfs_unmap_mtd(struct super_block *sb) +{ +} + +int axfs_copy_mtd(struct super_block *sb, void *dst, u64 fsoffset, u64 len) +{ + return -EINVAL; +} + +int axfs_get_sb_mtd(struct file_system_type *fs_type, int flags, + const char *dev_name, char *second_dev, + struct axfs_super *sbi, struct vfsmount *mnt, int *err) +{ + return FALSE; +} + +int axfs_is_dev_mtd(char *path, int *mtdnr) +{ + return FALSE; +} + +void axfs_kill_mtd_super(struct super_block *sb) +{ +} + +#endif /* CONFIG_MTD */ diff -Naur linux-2.6.26/fs/axfs/axfs_physmem.c linux-2.6.26-magellan/fs/axfs/axfs_physmem.c --- linux-2.6.26/fs/axfs/axfs_physmem.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/fs/axfs/axfs_physmem.c 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,77 @@ +/* + * Advanced XIP File System for Linux - AXFS + * Readonly, compressed, and XIP filesystem for Linux systems big and small + * + * Copyright(c) 2008 Numonyx + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * Authors: + * Jared Hulbert + * + * Project url: http://axfs.sourceforge.net + * + * axfs_physmem.c - + * Allows axfs to use striaght memory or has dummy functions if + * this is a UML system. + */ + +#include +#include +#ifdef CONFIG_UML + +void axfs_map_physmem(struct axfs_super *sbi, unsigned long size) +{ +} + +void axfs_unmap_physmem(struct super_block *sb) +{ +} + +#else +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) +#else +#include +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#ifdef ioremap_cached +#define AXFS_REMAP(a,b) (void __force *)ioremap_cached((a),(b)) +#else +#define AXFS_REMAP(a,b) (void __force *)ioremap((a),(b)) +#endif /* ioremap_cached */ +#else +#ifdef CONFIG_ARM +#define AXFS_REMAP(a,b) __ioremap((a),(b),L_PTE_CACHEABLE) +#else +#define AXFS_REMAP ioremap +#endif +#endif + +void axfs_map_physmem(struct axfs_super *sbi, unsigned long size) +{ + void *addr; + + if (AXFS_IS_PHYSMEM(sbi)) { + addr = AXFS_REMAP(sbi->phys_start_addr, size); + sbi->virt_start_addr = (unsigned long)addr; + } +} + +void axfs_unmap_physmem(struct super_block *sb) +{ + struct axfs_super *sbi = AXFS_SB(sb); + + if (!sbi) + return; + + if (AXFS_IS_PHYSMEM(sbi) && AXFS_VIRTADDR_IS_VALID(sbi)) { + iounmap((void *)(sbi->virt_start_addr)); + sbi->virt_start_addr = 0; + } +} + +#endif /* CONFIG_UML */ diff -Naur linux-2.6.26/fs/axfs/axfs_profiling.c linux-2.6.26-magellan/fs/axfs/axfs_profiling.c --- linux-2.6.26/fs/axfs/axfs_profiling.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/fs/axfs/axfs_profiling.c 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,602 @@ +/* + * Advanced XIP File System for Linux - AXFS + * Readonly, compressed, and XIP filesystem for Linux systems big and small + * + * Copyright(c) 2008 Numonyx + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * Authors: + * Eric Anderson + * Jared Hulbert + * Sujaya Srinivasan + * Justin Treon + * + * More info and current contacts at http://axfs.sourceforge.net + * + * axfs_profiling.c - + * Tracks pages of files that enter the page cache. Outputs through a proc + * file which generates a comma separated data file with path, page offset, + * count of times entered page cache. + */ + +#include +#ifdef CONFIG_AXFS_PROFILING +#include +#include +#include + +#define AXFS_PROC_DIR_NAME "axfs" + +struct axfs_profiling_manager { + struct axfs_profiling_data *profiling_data; + struct axfs_super *sbi; + u32 *dir_structure; + u32 size; +}; + +#define MAX_STRING_LEN 1024 + +/* Handles for our Directory and File */ +static struct proc_dir_entry *axfs_proc_dir; +static u32 proc_name_inc; + +/****************************************************************************** + * + * axfs_init_profile_dir_structure + * + * Description: + * Creates the structures for tracking the page usage data and creates the + * proc file that will be used to get the data. + * + * Parameters: + * (IN) manager - pointer to the profile manager for the filing system + * + * (IN) num_inodes - number of files in the system + * + * Returns: + * 0 + * + *****************************************************************************/ +static int axfs_init_profile_dir_structure(struct axfs_profiling_manager + *manager, u32 num_inodes) +{ + + struct axfs_super *sbi = (struct axfs_super *)manager->sbi; + u32 child_index = 0, i, j; + u32 *dir_structure = manager->dir_structure; + + /* loop through each inode in the image and find all + of the directories and mark their children */ + for (i = 0; i < num_inodes; i++) { + /* determine if the entry is a directory */ + if (!S_ISDIR(AXFS_GET_MODE(sbi, i))) + continue; + + /* get the index number for this directory */ + child_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, i); + + /* get the offset to its children */ + for (j = 0; j < AXFS_GET_INODE_NUM_ENTRIES(sbi, i); j++) { + if (dir_structure[child_index + j] != 0) { + printk(KERN_ERR + "axfs: ERROR inode was already set old " + "%lu new %lu\n", (unsigned long) + dir_structure[child_index + j], + (unsigned long)i); + } + dir_structure[child_index + j] = i; + } + } + + return 0; +} + +/****************************************************************************** + * + * axfs_get_directory_path + * + * Description: + * Determines the directory path of every file for printing the spreadsheet. + * + * Parameters: + * (IN) manager - Pointer to axfs profile manager + * + * (OUT) buffer - Pointer to the printable directory path for each file + * + * (IN) inode_number - Inode number of file to look up + * + * Returns: + * Size of the path to the file + * + * + **************************************************************************/ +static int axfs_get_directory_path(struct axfs_profiling_manager *manager, + char *buffer, u32 inode_number) +{ + u32 path_depth = 0; + u32 path_size = 0; + u32 string_len = 0; + u32 index = inode_number; + u32 dir_number; + u8 **path_array = NULL; + struct axfs_super *sbi = (struct axfs_super *)manager->sbi; + int i; + + /* determine how deep the directory path is and how big the name + string will be walk back until the root directory index is found + (index 0 is root) */ + while (manager->dir_structure[index] != 0) { + path_depth++; + /* set the index to the index of the parent directory */ + index = manager->dir_structure[index]; + } + + if (path_depth != 0) { + /* create an array that will hold a pointer for each of the + directories names */ + path_array = vmalloc(path_depth * sizeof(*path_array)); + if (path_array == NULL) { + printk(KERN_DEBUG + "axfs: directory_path vmalloc failed.\n"); + goto out; + } + } + + index = manager->dir_structure[inode_number]; + for (i = path_depth; i > 0; i--) { + /* get the array_index for the directory corresponding to + index */ + dir_number = AXFS_GET_INODE_ARRAY_INDEX(sbi, index); + + /* store a pointer to the name in the array */ + path_array[(i - 1)] = (u8 *) AXFS_GET_INODE_NAME(sbi, index); + + index = manager->dir_structure[index]; + } + + /* now print out the directory structure from the begining */ + string_len = sprintf(buffer, "./"); + path_size += string_len; + for (i = 0; i < path_depth; i++) { + buffer = buffer + string_len; + string_len = sprintf(buffer, "%s/", (char *)path_array[i]); + path_size += string_len; + } + + if (path_array != NULL) + vfree(path_array); + +out: + return path_size; + +} + +static ssize_t axfs_procfile_read(char *buffer, + char **buffer_location, + off_t offset, int buffer_length, int *eof, + void *data) +{ + struct axfs_profiling_manager *man; + struct axfs_profiling_data *profile; + struct axfs_super *sbi; + u64 array_index; + u64 loop_size, inode_page_offset, node_offset, inode_number; + u64 print_len = 0; + unsigned long addr; + int len = 0; + int i; + char *buff, *name = NULL; + + man = (struct axfs_profiling_manager *)data; + sbi = man->sbi; + + loop_size = man->size / sizeof(*profile); + + /* If all data has been returned set EOF */ + if (offset >= loop_size) { + *eof = 1; + return 0; + } + + buff = buffer; + /* print as much as the buffer can take */ + for (i = offset; i < loop_size; i++) { + + if ((print_len + MAX_STRING_LEN) > buffer_length) + break; + /* get the first profile data structure */ + profile = &(man->profiling_data[i]); + + if (profile->count == 0) + continue; + + inode_number = profile->inode_number; + + /* file names can be duplicated so we must print out the path */ + len = axfs_get_directory_path(man, buff, inode_number); + + print_len += len; + buff += len; + + /* get a pointer to the inode name */ + array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, inode_number); + name = (char *)AXFS_GET_INODE_NAME(sbi, inode_number); + + /* need to convert the page number in the node area to + the page number within the file */ + node_offset = i; + /* gives the offset of the node in the node list area + then substract that from the */ + inode_page_offset = node_offset - array_index; + + /* set everything up to print out */ + addr = (unsigned long)(inode_page_offset * PAGE_SIZE); + len = sprintf(buff, "%s,%lu,%lu\n", name, addr, profile->count); + + print_len += len; + buff += len; + } + + /* return the number of items printed. + This will be added to offset and passed back to us */ + *buffer_location = (char *)(i - offset); + + return print_len; +} + +static ssize_t axfs_procfile_write(struct file *file, + const char *buffer, unsigned long count, + void *data) +{ + struct axfs_profiling_manager *man_ptr = + (struct axfs_profiling_manager *)data; + + if ((count >= 2) && (0 == memcmp(buffer, "on", 2))) { + man_ptr->sbi->profiling_on = TRUE; + } else if ((count >= 3) && (0 == memcmp(buffer, "off", 3))) { + man_ptr->sbi->profiling_on = FALSE; + } else if ((count >= 5) && (0 == memcmp(buffer, "clear", 5))) { + memset(man_ptr->profiling_data, 0, man_ptr->size); + } else { + printk(KERN_INFO + "axfs: Unknown command. Supported options are:\n"); + printk(KERN_INFO "\t\"on\"\tTurn on profiling\n"); + printk(KERN_INFO "\t\"off\"\tTurn off profiling\n"); + printk(KERN_INFO "\t\"clear\"\tClear profiling buffer\n"); + } + + return count; +} + +static int axfs_create_proc_directory(void) +{ + if (axfs_proc_dir == NULL) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) + axfs_proc_dir = proc_mkdir(AXFS_PROC_DIR_NAME, NULL); +#else + axfs_proc_dir = proc_mkdir(AXFS_PROC_DIR_NAME, &proc_root); +#endif + if (!axfs_proc_dir) { + printk(KERN_WARNING + "axfs: Failed to create directory\n"); + return FALSE; + } + } + return TRUE; +} + +static void axfs_delete_proc_directory(void) +{ + /* Determine if there are any directory elements + and remove if all of the proc files are removed. */ + if (axfs_proc_dir != NULL) { + if (axfs_proc_dir->subdir == NULL) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) + remove_proc_entry(AXFS_PROC_DIR_NAME, NULL); +#else + remove_proc_entry(AXFS_PROC_DIR_NAME, &proc_root); +#endif + axfs_proc_dir = NULL; + } + } +} + +/****************************************************************************** + * + * axfs_delete_proc_file + * + * Description: + * Will search through the proc directory for the correct proc file, + * then delete it + * + * Parameters: + * (IN) sbi- axfs superblock pointer to determine which proc file to remove + * + * Returns: + * The profiling manager pointer for the proc file. + * + *****************************************************************************/ +static struct axfs_profiling_manager *axfs_delete_proc_file(struct axfs_super + *sbi) +{ + struct proc_dir_entry *current_proc_file; + struct axfs_profiling_manager *manager; + void *rv = NULL; + + if (!axfs_proc_dir) + return NULL; + + /* Walk through the proc file entries to find the matching sbi */ + current_proc_file = axfs_proc_dir->subdir; + + while (current_proc_file != NULL) { + manager = current_proc_file->data; + if (manager == NULL) { + printk(KERN_WARNING + "axfs: Error removing proc file private " + "data was NULL.\n"); + rv = NULL; + break; + } + if (manager->sbi == sbi) { + /* we found the match */ + remove_proc_entry(current_proc_file->name, + axfs_proc_dir); + rv = (void *)manager; + break; + } + current_proc_file = axfs_proc_dir->next; + } + return (struct axfs_profiling_manager *)rv; +} + +/****************************************************************************** + * + * axfs_register_profiling_proc + * + * Description: + * Will register the instance of the proc file for a given volume. + * + * Parameters: + * (IN) manager - Pointer to the profiling manager for the axfs volume + * + * Returns: + * 0 or error number + * + *****************************************************************************/ +static int axfs_register_profiling_proc(struct axfs_profiling_manager *manager) +{ + int rv = 0; + struct proc_dir_entry *proc_file; + char file_name[20]; + + if (!axfs_create_proc_directory()) { + rv = -ENOMEM; + goto out; + } + + sprintf(file_name, "volume%d", proc_name_inc); + proc_file = create_proc_entry(file_name, (mode_t) 0644, axfs_proc_dir); + if (proc_file == NULL) { + remove_proc_entry(file_name, axfs_proc_dir); + axfs_delete_proc_directory(); + rv = -ENOMEM; + goto out; + } + + proc_name_inc++; + proc_file->read_proc = axfs_procfile_read; + proc_file->write_proc = axfs_procfile_write; + proc_file->owner = THIS_MODULE; + proc_file->mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + proc_file->uid = 0; + proc_file->gid = 0; + proc_file->data = manager; + + printk(KERN_DEBUG "axfs: Proc entry created\n"); + +out: + return rv; +} + +/****************************************************************************** + * + * axfs_unregister_profiling_proc + * + * Description: + * Will unregister the instance of the proc file for the volume that was + * mounted. If this is the last volume mounted then the proc directory + * will also be removed. + * + * Parameters: + * (IN) sbi- axfs superblock pointer to determine which proc file to remove + * + * Returns: + * The profiling manager pointer for the proc file. + * + *****************************************************************************/ +static struct axfs_profiling_manager *axfs_unregister_profiling_proc(struct + axfs_super + *sbi) +{ + struct axfs_profiling_manager *manager; + manager = axfs_delete_proc_file(sbi); + axfs_delete_proc_directory(); + return manager; +} + +/****************************************************************************** + * + * axfs_init_profiling + * + * Description: + * Creates the structures for tracking the page usage data and creates the + * proc file that will be used to get the data. + * + * Parameters: + * (IN) sbi- axfs superblock pointer + * + * Returns: + * TRUE or FALSE + * + *****************************************************************************/ +int axfs_init_profiling(struct axfs_super *sbi) +{ + + u32 num_nodes, num_inodes; + struct axfs_profiling_manager *manager = NULL; + struct axfs_profiling_data *profile_data = NULL; + int err = -ENOMEM; + + /* determine the max number of pages in the FS */ + num_nodes = sbi->blocks; + if (!num_nodes) + return 0; + + manager = vmalloc(sizeof(*manager)); + if (!manager) + goto out; + + profile_data = vmalloc(num_nodes * sizeof(*profile_data)); + if (!profile_data) + goto out; + + memset(profile_data, 0, num_nodes * sizeof(*profile_data)); + + /* determine the max number of inodes in the FS */ + num_inodes = sbi->files; + + manager->dir_structure = vmalloc(num_inodes * sizeof(u32 *)); + if (!manager->dir_structure) + goto out; + + memset(manager->dir_structure, 0, (num_inodes * sizeof(u32 *))); + + manager->profiling_data = profile_data; + manager->size = num_nodes * sizeof(*profile_data); + manager->sbi = sbi; + sbi->profiling_on = TRUE; /* Turn on profiling by default */ + sbi->profile_data_ptr = profile_data; + + err = axfs_init_profile_dir_structure(manager, num_inodes); + if (err) + goto out; + + err = axfs_register_profiling_proc(manager); + if (err) + goto out; + + return 0; + +out: + if (manager->dir_structure) + vfree(manager->dir_structure); + if (profile_data) + vfree(profile_data); + if (manager) + vfree(manager); + return err; +} + +/****************************************************************************** + * + * axfs_shutdown_profiling + * + * Description: + * Remove the proc file for this volume and release the memory in the + * profiling manager + * + * Parameters: + * (IN) sbi- axfs superblock pointer + * + * Returns: + * TRUE or FALSE + * + *****************************************************************************/ +int axfs_shutdown_profiling(struct axfs_super *sbi) +{ + struct axfs_profiling_manager *manager; + /* remove the proc file for this volume and release the memory in the + profiling manager */ + + if (!sbi) + return TRUE; + + if (!sbi->profile_data_ptr) + return TRUE; + + manager = axfs_unregister_profiling_proc(sbi); + + if (manager == NULL) + return FALSE; + + if (manager->dir_structure) + vfree(manager->dir_structure); + if (manager->profiling_data) + vfree(manager->profiling_data); + if (manager) + vfree(manager); + return TRUE; +} + +/****************************************************************************** + * + * axfs_profiling_add + * + * Description: + * Log when a node is paged into memory by incrementing the count in the + * array profile data structure. + * + * Parameters: + * (IN) sbi- axfs superblock pointer + * + * (IN) array_index - The offset into the nodes table of file (node number) + * + * (IN) axfs_inode_number - Inode of the node to determine file name later + * + * Returns: + * none + * + *****************************************************************************/ +void axfs_profiling_add(struct axfs_super *sbi, unsigned long array_index, + unsigned int axfs_inode_number) +{ + unsigned long addr; + struct axfs_profiling_data *profile_data; + + if (sbi->profiling_on != TRUE) + return; + + addr = (unsigned long)sbi->profile_data_ptr; + addr += array_index * sizeof(*profile_data); + + profile_data = (struct axfs_profiling_data *)addr; + + /* Record the inode number to determine the file name later. */ + profile_data->inode_number = axfs_inode_number; + + /* Increment the number of times the node has been paged in */ + profile_data->count++; +} + +#else + +int axfs_init_profiling(struct axfs_super *sbi) +{ + return 0; +} + +int axfs_shutdown_profiling(struct axfs_super *sbi) +{ + return 0; +} + +void axfs_profiling_add(struct axfs_super *sbi, unsigned long array_index, + unsigned int axfs_inode_number) +{ +} + +#endif /* CONFIG_AXFS_PROFILING */ diff -Naur linux-2.6.26/fs/axfs/axfs_super.c linux-2.6.26-magellan/fs/axfs/axfs_super.c --- linux-2.6.26/fs/axfs/axfs_super.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/fs/axfs/axfs_super.c 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,1055 @@ +/* + * Advanced XIP File System for Linux - AXFS + * Readonly, compressed, and XIP filesystem for Linux systems big and small + * + * Copyright(c) 2008 Numonyx + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * Authors: + * Eric Anderson + * Jared Hulbert + * Sujaya Srinivasan + * Justin Treon + * + * More info and current contacts at http://axfs.sourceforge.net + * + * axfs_super.c - + * Contains the core code used to mount the fs. + * + */ + +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#include +#include +#else +#include +#include +#include +#endif +#include +#include +#include + +/******************** Function Declarations ****************************/ +static struct super_operations axfs_sops; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static struct axfs_super *axfs_get_sbi(void); +#endif +static void axfs_put_sbi(struct axfs_super *); +/***************** functions in other axfs files ***************************/ +int axfs_get_sb_bdev(struct file_system_type *, int, const char *, + struct axfs_super *, struct vfsmount *, int *); +void axfs_kill_block_super(struct super_block *); +int axfs_copy_block(struct super_block *, void *, u64, u64); +int axfs_is_dev_bdev(char *); +#ifndef NO_PHYSMEM +void axfs_map_physmem(struct axfs_super *, unsigned long); +void axfs_unmap_physmem(struct super_block *); +#endif +int axfs_map_mtd(struct super_block *); +void axfs_unmap_mtd(struct super_block *); +int axfs_copy_mtd(struct super_block *, void *, u64, u64); +int axfs_get_sb_mtd(struct file_system_type *, int, const char *, + struct axfs_super *, struct vfsmount *, int *); +int axfs_is_dev_mtd(char *, int *); +void axfs_kill_mtd_super(struct super_block *); +struct inode *axfs_create_vfs_inode(struct super_block *, int); +int axfs_get_uml_address(char *, unsigned long *, unsigned long *); +int axfs_init_profiling(struct axfs_super *); +int axfs_shutdown_profiling(struct axfs_super *); +void axfs_profiling_add(struct axfs_super *, unsigned long, unsigned int); +struct inode *axfs_create_vfs_inode(struct super_block *, int); +/******************************************************************************/ + +static void axfs_free_region(struct axfs_super *sbi, + struct axfs_region_desc *region) +{ + if (!region) + return; + + if (AXFS_IS_REGION_XIP(sbi, region)) + return; + + if (region->virt_addr) + vfree(region->virt_addr); +} + +static void axfs_put_sbi(struct axfs_super *sbi) +{ + if (!sbi) + return; + + axfs_shutdown_profiling(sbi); + + 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); + + if (sbi->second_dev) + kfree(sbi->second_dev); + + if (sbi->cblock_buffer[0]) + vfree(sbi->cblock_buffer[0]); + if (sbi->cblock_buffer[1]) + vfree(sbi->cblock_buffer[1]); + + kfree(sbi); +} + +static void axfs_put_super(struct super_block *sb) +{ + axfs_unmap_mtd(sb); +#ifndef NO_PHYSMEM + axfs_unmap_physmem(sb); +#endif + axfs_put_sbi(AXFS_SB(sb)); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + sb->s_fs_info = NULL; +#endif +} + +static int 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); + 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; + + /* Catches case where sbi is not yet fully initialized. */ + if ((sbi->magic == 0) && (sbi->virt_start_addr != 0)) + return axfs_copy_mem(sb, buf, fsoffset, len); + + 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)) { + err = axfs_copy_mem(sb, buf, fsoffset, len); + } else if (AXFS_HAS_MTD(sb)) { + err = axfs_copy_mtd(sb, buf, fsoffset, len); + } else if (AXFS_HAS_BDEV(sb)) { + err = axfs_copy_block(sb, buf, fsoffset, len); + } else { + err = -EINVAL; + } + } + } else { + if (AXFS_NODEV(sb)) { + err = axfs_copy_mem(sb, buf, fsoffset, len); + } else if (AXFS_HAS_BDEV(sb)) { + err = axfs_copy_block(sb, buf, fsoffset, len); + } else if (AXFS_HAS_MTD(sb)) { + err = axfs_copy_mtd(sb, buf, fsoffset, len); + } else { + err = -EINVAL; + } + } + 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: + if (buff) + vfree(buff); + if (region->virt_addr) + vfree(region->virt_addr); + return err; +} + +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_init_cblock_buffers(struct axfs_super *sbi) +{ + sbi->current_cnode_index = -1; + sbi->cblock_buffer[0] = vmalloc(sbi->cblock_size); + sbi->cblock_buffer[1] = vmalloc(sbi->cblock_size); + if ((!sbi->cblock_buffer[0]) || (!sbi->cblock_buffer[1])) + return -ENOMEM; + + return 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; + } + return err; +} + +static void axfs_fill_region_desc(struct super_block *sb, + struct axfs_region_desc_onmedia *out, + u64 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; +} + +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; + + out = kmalloc(sizeof(*out), GFP_KERNEL); + if (!out) + return -ENOMEM; + memset(out, 0, sizeof(*out)); + + 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; +} + +int axfs_set_compression_type(struct axfs_super *sbi) +{ + if (sbi->compression_type != ZLIB) + return -EINVAL; + + return 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\n"); + err = -EINVAL; + 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); + 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; + + err = axfs_set_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); + if (err) + goto out; + + err = 0; +out: + kfree(sbo); +#ifndef NO_PHYSMEM + axfs_unmap_physmem(sb); +#endif + return err; +} + +/* Verify that the size of the block segment of a split filesystem + is less than or equal to that of the device containing it. + Validation of the size of an mmap segment vs. the device containing + it is handled by the point() function in axfs_map_mtd. +*/ +int axfs_verify_device_sizes(struct super_block *sb) +{ + struct axfs_super *sbi = AXFS_SB(sb); + struct mtd_info *mtd0 = AXFS_MTD(sb); + struct mtd_info *mtd1 = AXFS_MTD1(sb); + int sndsize = sbi->size - sbi->mmap_size; + + /* Whole FS on one device */ + if (mtd0 && !mtd1 && (mtd0->size < sbi->size)) { + printk(KERN_ERR "axfs: ERROR: Filesystem extends beyond end of" + "MTD! Filesystem cannot be safely mounted!\n"); + printk(KERN_ERR "mtd name: %s, mtd size: 0x%x," + " fs size: 0x%llx\n", mtd0->name, mtd0->size, sbi->size); + return -EINVAL; + } + + /* Split filesystem using physaddr */ + if (sndsize && !mtd0 && mtd1 && (mtd1->size < sndsize)) { + printk(KERN_ERR "axfs: ERROR: The specified second_dev device " + "is smaller than the store and download segment!\n"); + printk(KERN_ERR "mtd name: %s, mtd size: 0x%x, " + "snd size: 0x%x\n", mtd1->name, mtd1->size, sndsize); + return -EINVAL; + } + + /* Split filesystem using two devices */ + if (sndsize && mtd0 && mtd1) { + if (mtd0->size < sbi->mmap_size) { + printk(KERN_ERR "axfs: ERROR: Mmap segment extends" + " beyond end of MTD!"); + printk(KERN_ERR "mtd name: %s, mtd size: 0x%x, mmap " + "size: 0x%llx", + mtd0->name, mtd0->size, sbi->mmap_size); + return -EINVAL; + } + if (mtd1->size < sndsize) { + printk(KERN_ERR "axfs: ERROR: The specified second_dev " + "device is smaller than the store and download " + "segment!\n"); + printk(KERN_ERR "mtd name: %s, mtd size: 0x%x, " + "snd size: 0x%x\n", + mtd1->name, mtd1->size, sndsize); + return -EINVAL; + } + } + + return 0; +} + +/* Read the last four bytes of the volume and make sure the AXFS magic is + present. */ +int axfs_verify_eofs_magic(struct super_block *sb) +{ + struct axfs_super *sbi = AXFS_SB(sb); + u32 buf = 0; + int err; + u32 fsoffset = sbi->size - sizeof(u32); + int len = sizeof(u32); + + err = axfs_copy_metadata(sb, &buf, fsoffset, len); + + if (err) + return -EINVAL; + + if (be32_to_cpu(buf) != AXFS_MAGIC) { + printk(KERN_ERR "READ: 0x%x\n", be32_to_cpu(buf)); + printk(KERN_ERR "ERROR: Filesystem is incomplete and cannot be " + "mounted!\n"); + return -EINVAL; + } + + 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"); + 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; +} +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#else + +static int axfs_check_options(char *, struct axfs_super *); +int axfs_set_block_size(struct super_block *); +static int axfs_get_sb_address(struct axfs_super *, int *); + +int axfs_find_devs(struct super_block *sb, void *data) +{ + struct axfs_super *sbi = AXFS_SB(sb); + int err; + + err = axfs_check_options((char *)data, sbi); + if(err) + goto out; + + /* set block_size for any block devices */ + err = axfs_set_block_size(sb); + if(err) + goto out; + + /* Check if physaddr is valid */ + if(axfs_get_sb_address(sbi, &err)) + goto out; + + /* Now we assume it's a block device */ + if(sb->s_bdev) + goto out; + + printk(KERN_ERR "axfs: no valid devices found\n"); + + err = -EINVAL; /*No SB found*/ + +out: + + return err; +} +#endif + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +int axfs_fill_super(struct super_block *sb, void *data, int silent) +#else +struct super_block *axfs_read_super(struct super_block *sb, void *data, int silent) +#endif +{ + struct axfs_super *sbi; + struct inode *root; + int err; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + struct axfs_super *sbi_in = (struct axfs_super *)data; + sbi = axfs_get_sbi(); + sb->s_fs_info = (void *)sbi; + + memcpy(sbi, sbi_in, sizeof(*sbi)); +#else + + sbi = AXFS_SB(sb); + + err = axfs_find_devs(sb, data); +#endif + + /* fully populate the incore superblock structures */ + err = axfs_do_fill_super(sb); + if (err) + goto out; + + sb->s_flags |= MS_RDONLY; + + /* Setup the VFS super block now */ + sb->s_op = &axfs_sops; + root = axfs_create_vfs_inode(sb, 0); + if (!root) { + err = -EINVAL; + goto out; + } + + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + iput(root); + err = -EINVAL; + goto out; + } + + err = axfs_init_profiling(sbi); + if (err) + goto out; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + return 0; +#else + return sb; +#endif + +out: + axfs_put_super(sb); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + return err; +#else + return NULL; +#endif +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static int axfs_get_sb_address(struct file_system_type *fs_type, int flags, + struct axfs_super *sbi, struct vfsmount *mnt, + int *err) +{ + int mtdnr; + char *sd = sbi->second_dev; +#else +static int axfs_get_sb_address(struct axfs_super *sbi, int *err) +{ +#endif + + if (sbi->phys_start_addr == 0) + return FALSE; + + if (sbi->phys_start_addr & (PAGE_SIZE - 1)) { + printk(KERN_ERR + "axfs: address 0x%lx for axfs image isn't aligned" + " to a page boundary\n", sbi->phys_start_addr); + *err = -EINVAL; + return TRUE; + } + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + if (axfs_is_dev_mtd(sd, &mtdnr)) { + return axfs_get_sb_mtd(fs_type, flags, sd, sbi, mnt, err); + } else if (axfs_is_dev_bdev(sd)) { + return axfs_get_sb_bdev(fs_type, flags, sd, sbi, mnt, err); + } else { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) + *err = get_sb_nodev(fs_type, flags, sbi, axfs_fill_super, mnt); +#else + mnt->mnt_sb = + get_sb_nodev(fs_type, flags, (void *)sbi, axfs_fill_super); +#endif + } +#endif + + return TRUE; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +/* helpers for parse_axfs_options */ +enum { + OPTION_ERR, + OPTION_SECOND_DEV, + OPTION_PHYSICAL_ADDRESS_LOWER_X, + OPTION_PHYSICAL_ADDRESS_UPPER_X, + OPTION_IOMEM +}; + +/* helpers for parse_axfs_options */ +static match_table_t tokens = { + {OPTION_SECOND_DEV, "second_dev=%s"}, + {OPTION_PHYSICAL_ADDRESS_LOWER_X, "physaddr=0x%s"}, + {OPTION_PHYSICAL_ADDRESS_UPPER_X, "physaddr=0X%s"}, + {OPTION_IOMEM, "iomem=%s"}, + {OPTION_ERR, NULL} +}; +#endif + +static int axfs_check_options(char *options, struct axfs_super *sbi) +{ + int err = -EINVAL; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + unsigned long address = 0; + char *iomem = NULL; + unsigned long length = 0; + char *p; + substring_t args[MAX_OPT_ARGS]; + + if (!options) + return 0; + + if (!*options) + return 0; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + if (!*p) + continue; + + token = match_token(p, tokens, args); + switch (token) { + case OPTION_SECOND_DEV: + sbi->second_dev = match_strdup(&args[0]); + if (!(sbi->second_dev)) { + err = -ENOMEM; + goto out; + } + if (!*(sbi->second_dev)) + goto bad_value; + break; + case OPTION_IOMEM: + iomem = match_strdup(&args[0]); + if (!(iomem)) { + err = -ENOMEM; + goto out; + } + if (!*iomem) + goto bad_value; + break; + case OPTION_PHYSICAL_ADDRESS_LOWER_X: + case OPTION_PHYSICAL_ADDRESS_UPPER_X: + if (match_hex(&args[0], (int *)&address)) + goto out; + if (!address) + goto bad_value; + break; + default: + printk(KERN_ERR + "axfs: unrecognized mount option \"%s\" " + "or missing value\n", p); + goto out; + } + } + + if (iomem) { + if (address) + goto out; + err = axfs_get_uml_address(iomem, &address, &length); + kfree(iomem); + sbi->iomem_size = length; + sbi->virt_start_addr = address; + } + + sbi->phys_start_addr = address; + return 0; + +bad_value: + printk(KERN_ERR + "axfs: unrecognized mount option \"%s\" " + "or missing value\n", p); + +out: + if (iomem) + kfree(iomem); +#else + char *key; + char *value; + char *end; + + sbi->phys_start_addr = 0; + err = 0; + + if(!options) { + goto out; + } + + for(key = strtok(options, ","); key != NULL; key = strtok (NULL, ",")) { + if((value = strchr(key, '=')) != NULL) { + if(*value == 0) { + err = -EINVAL; + goto out; + } + *value = 0; + value++; + } + if(!strcmp(key,"physaddr")) { + if(value != NULL) + sbi->phys_start_addr = simple_strtoul(value,&end,0); + } + } + +out: +#endif + return err; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) +int axfs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data, struct vfsmount *mnt) +#else +struct super_block *axfs_get_sb(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) +#endif +{ + struct axfs_super *sbi; + int err; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) +#else + struct super_block *sb; + struct vfsmount *mnt; + mnt = kmalloc(sizeof(*mnt), GFP_KERNEL); + memset(mnt, 0, sizeof(*mnt)); +#endif + + sbi = axfs_get_sbi(); + if (IS_ERR(sbi)) +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) + return PTR_ERR(sbi); +#else + return (struct super_block *)sbi; +#endif + + err = axfs_check_options((char *)data, sbi); + if (err) + goto out; + + /* First we check if we are mounting directly to memory */ + if (axfs_get_sb_address(fs_type, flags, sbi, mnt, &err)) + goto out; + + /* Next we assume there's a MTD device */ + if (axfs_get_sb_mtd(fs_type, flags, dev_name, sbi, mnt, &err)) + goto out; + + /* Now we assume it's a block device */ + if (sbi->second_dev) { + printk(KERN_ERR + "axfs: can't specify secondary block device %s because" + " %s is assumed to be a block device\n", sbi->second_dev, + dev_name); + err = -EINVAL; + goto out; + } + + if (axfs_get_sb_bdev(fs_type, flags, dev_name, sbi, mnt, &err)) + goto out; + + err = -EINVAL; + +out: + axfs_put_sbi(sbi); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) + return err; +#else + if (err) + return ERR_PTR(err); + + sb = mnt->mnt_sb; + kfree(mnt); + return sb; +#endif +} + +static struct axfs_super *axfs_get_sbi(void) +{ + struct axfs_super *sbi; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13) + sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); +#else + sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); + memset(sbi, 0, sizeof(*sbi)); +#endif + if (sbi) + return sbi; + + axfs_put_sbi(sbi); + return ERR_PTR(-ENOMEM); +} + +static void axfs_kill_super(struct super_block *sb) +{ + if (AXFS_NODEV(sb)) + return kill_anon_super(sb); + + if (AXFS_HAS_MTD(sb)) + axfs_kill_mtd_super(sb); + + if (AXFS_HAS_BDEV(sb)) + axfs_kill_block_super(sb); +} +#endif + +static int axfs_remount(struct super_block *sb, int *flags, char *data) +{ + *flags |= MS_RDONLY; + return 0; +} + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) +static int axfs_statfs(struct dentry *dentry, struct kstatfs *buf) +#elif LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static int axfs_statfs(struct super_block *sb, struct kstatfs *buf) +#else +static int axfs_statfs(struct super_block *sb, struct statfs *buf) +#endif +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17) + struct axfs_super *sbi = AXFS_SB(dentry->d_sb); +#else + struct axfs_super *sbi = AXFS_SB(sb); +#endif + + buf->f_type = AXFS_MAGIC; + buf->f_bsize = AXFS_PAGE_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 struct super_operations axfs_sops = { + .put_super = axfs_put_super, + .remount_fs = axfs_remount, + .statfs = axfs_statfs, +}; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +static struct file_system_type axfs_fs_type = { + .owner = THIS_MODULE, + .name = "axfs", + .get_sb = axfs_get_sb, + .kill_sb = axfs_kill_super, +}; +#else +DECLARE_FSTYPE(axfs_fs_type, "axfs", axfs_read_super, 0); +DECLARE_FSTYPE_DEV(axfs_bdev_fs_type, "axfs_bdev", axfs_read_super); +#endif + +static int __init init_axfs_fs(void) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) + axfs_uncompress_init(); +#else + int rv; + + axfs_uncompress_init(); + rv = register_filesystem(&axfs_bdev_fs_type); + if(rv) + return rv; +#endif + return register_filesystem(&axfs_fs_type); +} + +static void __exit exit_axfs_fs(void) +{ + axfs_uncompress_exit(); + unregister_filesystem(&axfs_fs_type); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#else + unregister_filesystem(&axfs_bdev_fs_type); +#endif +} + +module_init(init_axfs_fs); +module_exit(exit_axfs_fs); +MODULE_LICENSE("GPL"); diff -Naur linux-2.6.26/fs/axfs/axfs_uml.c linux-2.6.26-magellan/fs/axfs/axfs_uml.c --- linux-2.6.26/fs/axfs/axfs_uml.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/fs/axfs/axfs_uml.c 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,47 @@ +/* + * Advanced XIP File System for Linux - AXFS + * Readonly, compressed, and XIP filesystem for Linux systems big and small + * + * Copyright(c) 2008 Numonyx + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * Authors: + * Jared Hulbert + * + * Project url: http://axfs.sourceforge.net + * + * axfs_uml.c - + * Allows axfs to a UML kernels find_iomem() interface as an XIP device or + * dummy functions if this is not a UML build. + */ + +#include +#ifdef CONFIG_UML +#include +int axfs_get_uml_address(char *iomem, unsigned long *address, + unsigned long *length) +{ + *address = find_iomem(iomem, length); + if (!(*address)) { + printk(KERN_DEBUG "axfs: find_iomem() failed\n"); + return -EINVAL; + } + + if (*length < PAGE_SIZE) { + printk(KERN_DEBUG + "axfs: iomem() too small, must be at least %li Bytes\n", + PAGE_SIZE); + return -EINVAL; + } + return 0; +} +#else +int axfs_get_uml_address(char *iomem, unsigned long *address, + unsigned long *length) +{ + return 0; +} +#endif /* CONFIG_UML */ diff -Naur linux-2.6.26/fs/axfs/axfs_uncompress.c linux-2.6.26-magellan/fs/axfs/axfs_uncompress.c --- linux-2.6.26/fs/axfs/axfs_uncompress.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/fs/axfs/axfs_uncompress.c 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,124 @@ +/* + * Advanced XIP File System for Linux - AXFS + * Readonly, compressed, and XIP filesystem for Linux systems big and small + * + * Modified in 2006 by Eric Anderson + * from the cramfs sources fs/cramfs/uncompress.c + * + * (C) Copyright 1999 Linus Torvalds + * + * axfs_uncompress.c - + * axfs interfaces to the uncompression library. There's really just + * three entrypoints: + * + * - axfs_uncompress_init() - called to initialize the thing. + * - axfs_uncompress_exit() - tell me when you're done + * - axfs_uncompress_block() - uncompress a block. + * + * NOTE NOTE NOTE! The uncompression is entirely single-threaded. We + * only have one stream, and we'll initialize it only once even if it + * then is used by multiple filesystems. + * + */ + +#ifndef ALL_VERSIONS +#include /* For multi-version support */ +#endif +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) +#include +#else +#include +#endif + +static z_stream stream; +static int initialized; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) +static struct mutex axfs_uncmp_mutex; +#else +static struct rw_semaphore axfs_uncmp_mutex; +#endif + +int axfs_uncompress_block(void *dst, int dstlen, void *src, int srclen) +{ + int err; + int out; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) + mutex_lock(&axfs_uncmp_mutex); +#else + down_write(&axfs_uncmp_mutex); +#endif + + stream.next_in = src; + stream.avail_in = srclen; + + stream.next_out = dst; + stream.avail_out = dstlen; + + err = zlib_inflateReset(&stream); + if (err != Z_OK) { + printk(KERN_ERR "zlib_inflateReset error %d\n", err); + zlib_inflateEnd(&stream); + zlib_inflateInit(&stream); + } + + err = zlib_inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) + goto err; + + out = stream.total_out; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) + mutex_unlock(&axfs_uncmp_mutex); +#else + up_write(&axfs_uncmp_mutex); +#endif + + return out; + +err: + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) + mutex_unlock(&axfs_uncmp_mutex); +#else + up_write(&axfs_uncmp_mutex); +#endif + + printk(KERN_ERR "Error %d while decompressing!\n", err); + printk(KERN_ERR "%p(%d)->%p(%d)\n", src, srclen, dst, dstlen); + return 0; +} + +int axfs_uncompress_init(void) +{ + if (!initialized++) { + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15) + mutex_init(&axfs_uncmp_mutex); +#else + init_rwsem(&axfs_uncmp_mutex); +#endif + + stream.workspace = vmalloc(zlib_inflate_workspacesize()); + if (!stream.workspace) { + initialized = 0; + return -ENOMEM; + } + stream.next_in = NULL; + stream.avail_in = 0; + zlib_inflateInit(&stream); + } + return 0; +} + +int axfs_uncompress_exit(void) +{ + if (!--initialized) { + zlib_inflateEnd(&stream); + vfree(stream.workspace); + } + return 0; +} diff -Naur linux-2.6.26/fs/axfs/Makefile linux-2.6.26-magellan/fs/axfs/Makefile --- linux-2.6.26/fs/axfs/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/fs/axfs/Makefile 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,7 @@ +# +# Makefile for the linux axfs routines +# + +obj-$(CONFIG_AXFS) += axfs.o + +axfs-objs := axfs_inode.o axfs_super.o axfs_uncompress.o axfs_profiling.o axfs_uml.o axfs_mtd.o axfs_bdev.o axfs_physmem.o diff -Naur linux-2.6.26/fs/Kconfig linux-2.6.26-magellan/fs/Kconfig --- linux-2.6.26/fs/Kconfig 2008-09-17 22:07:58.000000000 +0200 +++ linux-2.6.26-magellan/fs/Kconfig 2008-09-17 22:08:33.000000000 +0200 @@ -1076,6 +1076,27 @@ menu "Miscellaneous filesystems" +config AXFS + tristate "Advanced XIP File System (AXFS) support (EXPERIMENTAL)" + select FS_XIP + select ZLIB_INFLATE + default n + help + The Advanced XIP File System or (AXFS) is a highly compressed + readonly filesystem like cramfs or squashfs. It also can be + configured to store individual pages of files compressed or + uncompressed as XIP pages. This allows for faster boot up and + application launch time with a smaller memory footprint. + +config AXFS_PROFILING + bool "Profiling extensions for AXFS (EXPERIMENTAL)" + depends on AXFS + default n + help + Profiling tooling used to identify what pages in the filesystem + image are actually accessed and how much. + + config ADFS_FS tristate "ADFS file system support (EXPERIMENTAL)" depends on BLOCK && EXPERIMENTAL diff -Naur linux-2.6.26/fs/Makefile linux-2.6.26-magellan/fs/Makefile --- linux-2.6.26/fs/Makefile 2008-09-17 22:07:58.000000000 +0200 +++ linux-2.6.26-magellan/fs/Makefile 2008-09-17 22:08:33.000000000 +0200 @@ -74,6 +74,7 @@ obj-$(CONFIG_JBD2) += jbd2/ obj-$(CONFIG_EXT2_FS) += ext2/ obj-$(CONFIG_CRAMFS) += cramfs/ +obj-$(CONFIG_AXFS) += axfs/ obj-$(CONFIG_SQUASHFS) += squashfs/ obj-y += ramfs/ obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ diff -Naur linux-2.6.26/include/linux/axfs.h linux-2.6.26-magellan/include/linux/axfs.h --- linux-2.6.26/include/linux/axfs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26-magellan/include/linux/axfs.h 2008-09-17 22:08:33.000000000 +0200 @@ -0,0 +1,393 @@ +/* + * Advanced XIP File System for Linux - AXFS + * Readonly, compressed, and XIP filesystem for Linux systems big and small + * + * Copyright(c) 2008 Numonyx + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * Authors: + * Eric Anderson + * Jared Hulbert + * Sujaya Srinivasan + * Justin Treon + * + * Project url: http://axfs.sourceforge.net + */ + +#ifndef __AXFS_H +#define __AXFS_H + +#ifndef ALL_VERSIONS +#include /* For multi-version support */ +#endif + +#ifdef __KERNEL__ +#include +#endif +#include +#include + +#define AXFS_MAGIC 0x48A0E4CD /* some random number */ +#define AXFS_SIGNATURE "Advanced XIP FS" +#define AXFS_MAXPATHLEN 255 + +/* Uncompression interfaces to the underlying zlib */ +int axfs_uncompress_block(void *, int, void *, int); +int axfs_uncompress_init(void); +int axfs_uncompress_exit(void); + +struct axfs_profiling_data { + u64 inode_number; + unsigned long count; +}; + +enum axfs_node_types { + XIP = 0, + Compressed, + Byte_Aligned, +}; + +enum axfs_compression_types { + ZLIB = 0 +}; + +/* + * on media struct describing a data region + */ +struct axfs_region_desc_onmedia { + u64 fsoffset; + u64 size; + u64 compressed_size; + u64 max_index; + u8 table_byte_depth; + u8 incore; +}; + +struct axfs_region_desc { + u64 fsoffset; + u64 size; + u64 compressed_size; + u64 max_index; + void *virt_addr; + u8 table_byte_depth; + u8 incore; +}; + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) +#else +struct axfs_fill_super_info { + struct axfs_super_onmedia *onmedia_super_block; + unsigned long physical_start_address; + unsigned long virtual_start_address; +}; +#endif +/* + * axfs_super is the on media format for the super block it must be big endian + */ +struct axfs_super_onmedia { + u32 magic; /* 0x48A0E4CD - random number */ + u8 signature[16]; /* "Advanced XIP FS" */ + u8 digest[40]; /* sha1 digest for checking data integrity */ + u32 cblock_size; /* maximum size of the block being compressed */ + u64 files; /* number of inodes/files in fs */ + u64 size; /* total image size */ + u64 blocks; /* number of nodes in fs */ + u64 mmap_size; /* size of the memory mapped part of image */ + u64 strings; /* offset to strings region descriptor */ + u64 xip; /* offset to xip region descriptor */ + u64 byte_aligned; /* offset to the byte aligned region desc */ + u64 compressed; /* offset to the compressed region desc */ + u64 node_type; /* offset to node type region desc */ + u64 node_index; /* offset to node index region desc */ + u64 cnode_offset; /* offset to cnode offset region desc */ + u64 cnode_index; /* offset to cnode index region desc */ + u64 banode_offset; /* offset to banode offset region desc */ + u64 cblock_offset; /* offset to cblock offset region desc */ + u64 inode_file_size; /* offset to inode file size desc*/ + u64 inode_name_offset; /* offset to inode num_entries region desc */ + u64 inode_num_entries; /* offset to inode num_entries region desc */ + u64 inode_mode_index; /* offset to inode mode index region desc */ + u64 inode_array_index; /* offset to inode node index region desc */ + u64 modes; /* offset to mode mode region desc */ + u64 uids; /* offset to mode uid index region desc */ + u64 gids; /* offset to mode gid index region desc */ + u8 version_major; + u8 version_minor; + u8 version_sub; + u8 compression_type; /* Identifies type of compression used on FS */ + u64 timestamp; /* UNIX time_t of filesystem build time */ +}; + +/* + * axfs super-block data in core + */ +struct axfs_super { + u32 magic; + u8 version_major; + u8 version_minor; + u8 version_sub; + u8 padding; + u64 files; + u64 size; + u64 blocks; + u64 mmap_size; + struct axfs_region_desc strings; + struct axfs_region_desc xip; + struct axfs_region_desc compressed; + struct axfs_region_desc byte_aligned; + struct axfs_region_desc node_type; + struct axfs_region_desc node_index; + struct axfs_region_desc cnode_offset; + struct axfs_region_desc cnode_index; + struct axfs_region_desc banode_offset; + struct axfs_region_desc cblock_offset; + struct axfs_region_desc inode_file_size; + struct axfs_region_desc inode_name_offset; + struct axfs_region_desc inode_num_entries; + struct axfs_region_desc inode_mode_index; + struct axfs_region_desc inode_array_index; + struct axfs_region_desc modes; + struct axfs_region_desc uids; + struct axfs_region_desc gids; + unsigned long phys_start_addr; + unsigned long virt_start_addr; + char *second_dev; + unsigned long iomem_size; + void *mtd0; /* primary device */ + void *mtd1; /* secondary device */ + u32 cblock_size; + u64 current_cnode_index; + void *cblock_buffer[2]; + struct rw_semaphore lock; + struct axfs_profiling_data *profile_data_ptr; + u8 profiling_on; /* Determines if profiling is on or off */ + u8 mtd_pointed; + u8 compression_type; + struct timespec timestamp; +}; + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define AXFS_PAGE_SIZE 4096 + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0) +#define AXFS_SB(sb) (struct axfs_super *)((sb)->s_fs_info) +#else +#define AXFS_SB(sb) (struct axfs_super *) &((sb)->u.axfs_sb) +#endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,21) +#define AXFS_MTD(sb) (void *)((sb)->s_mtd) +#else +#define AXFS_MTD(sb) 0 +#endif +#define AXFS_MTD0(sb) (((AXFS_SB(sb))->mtd0) ? \ + ((AXFS_SB(sb))->mtd0) : (AXFS_MTD(sb))) +#define AXFS_MTD1(sb) ((AXFS_SB(sb))->mtd1) + +#define AXFS_BDEV(sb) ((sb)->s_bdev) + +#define AXFS_HAS_BDEV(sb) \ + ((AXFS_BDEV(sb) != NULL) ? TRUE : FALSE) +#define AXFS_HAS_MTD(sb) \ + (((AXFS_MTD0(sb) != NULL) || \ + (AXFS_MTD1(sb) != NULL) || \ + (AXFS_MTD(sb) != NULL)) ? TRUE : FALSE) + +#define AXFS_NODEV(sb) \ + ((!AXFS_HAS_MTD(sb) && !AXFS_HAS_BDEV(sb)) ? TRUE : FALSE) + +static inline u64 axfs_bytetable_stitch(u8 depth, u8 *table, u64 index) +{ + u64 i; + u64 output = 0; + u64 byte = 0; + u64 j; + u64 bits; + + for (i = 0; i < depth; i++) { + j = index * depth + i; + bits = 8 * (depth - i - 1); + byte = table[j]; + output += byte << bits; + } + return output; +} + +#define AXFS_GET_BYTETABLE_VAL(desc,index) \ + axfs_bytetable_stitch(((struct axfs_region_desc)(desc)).table_byte_depth,\ + (u8 *)((struct axfs_region_desc)(desc)).virt_addr, index) + +#define AXFS_GET_NODE_TYPE(sbi,node_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->node_type,\ + (node_index)) + +#define AXFS_GET_NODE_INDEX(sbi,node__index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->node_index,\ + (node__index)) + +#define AXFS_IS_NODE_XIP(sbi,node_index) \ + (AXFS_GET_NODE_TYPE(sbi, (node_index)) == XIP) + +#define AXFS_GET_CNODE_INDEX(sbi,node_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->cnode_index,\ + (node_index)) + +#define AXFS_GET_CNODE_OFFSET(desc,node_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->cnode_offset,\ + (node_index)) + +#define AXFS_GET_BANODE_OFFSET(desc,node_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->banode_offset,\ + (node_index)) + +#define AXFS_GET_CBLOCK_OFFSET(desc,node_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->cblock_offset,\ + (node_index)) + +#define AXFS_GET_INODE_FILE_SIZE(sbi,inode_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_file_size,\ + (inode_index)) + +#define AXFS_GET_INODE_NAME_OFFSET(sbi,inode_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_name_offset,\ + (inode_index)) + +#define AXFS_GET_INODE_NUM_ENTRIES(sbi,inode_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_num_entries,\ + (inode_index)) + +#define AXFS_GET_INODE_MODE_INDEX(sbi,inode_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_mode_index,\ + (inode_index)) + +#define AXFS_GET_INODE_ARRAY_INDEX(sbi,inode_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->inode_array_index,\ + (inode_index)) + +#define AXFS_GET_MODE(sbi,mode_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->modes,\ + (AXFS_GET_INODE_MODE_INDEX(sbi, (mode_index)))) + +#define AXFS_GET_UID(sbi,mode_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->uids,\ + (AXFS_GET_INODE_MODE_INDEX(sbi, (mode_index)))) + +#define AXFS_GET_GID(sbi,mode_index) \ + AXFS_GET_BYTETABLE_VAL(((struct axfs_super *)(sbi))->gids,\ + (AXFS_GET_INODE_MODE_INDEX(sbi, (mode_index)))) + +#define AXFS_IS_REGION_COMPRESSED(_region) \ + (( \ + ((struct axfs_region_desc *)(_region))->compressed_size > \ + 0 \ + ) ? TRUE : FALSE) + +#define AXFS_PHYSADDR_IS_VALID(sbi) \ + (((((struct axfs_super *)(sbi))->phys_start_addr) > 0 \ + ) ? TRUE : FALSE) + +#define AXFS_VIRTADDR_IS_VALID(sbi) \ + (((((struct axfs_super *)(sbi))->virt_start_addr) > 0 \ + ) ? TRUE : FALSE) + +#define AXFS_IS_IOMEM(sbi) \ + (((((struct axfs_super *)(sbi))->iomem_size) > 0) ? TRUE : FALSE) + +#define AXFS_IS_POINTED(sbi) \ + (((((struct axfs_super *)(sbi))->mtd_pointed) > 0) ? TRUE : FALSE) + +static inline int axfs_can_xip(struct axfs_super *sbi) +{ + if (AXFS_IS_POINTED(sbi)) { + if(!AXFS_PHYSADDR_IS_VALID(sbi)) + return FALSE; + } + + if (!AXFS_VIRTADDR_IS_VALID(sbi)) + return FALSE; + + return TRUE; +} + +#define AXFS_IS_PHYSMEM(sbi) \ + (( \ + AXFS_PHYSADDR_IS_VALID(sbi) \ + && !AXFS_IS_IOMEM(sbi) \ + && !AXFS_IS_POINTED(sbi) \ + ) ? TRUE : FALSE) + +#define AXFS_IS_MMAPABLE(sbi,offset) \ + ((\ + (((struct axfs_super *)(sbi))->mmap_size) > (offset) \ + ) ? TRUE : FALSE) + +#define AXFS_IS_OFFSET_MMAPABLE(sbi,offset) \ + (( \ + AXFS_IS_MMAPABLE(sbi, offset) && AXFS_VIRTADDR_IS_VALID(sbi) \ + ) ? TRUE : FALSE) + +#define AXFS_IS_REGION_MMAPABLE(sbi,_region) \ + (( \ + AXFS_IS_MMAPABLE(sbi, ((struct axfs_region_desc *)(_region))->fsoffset) \ + && AXFS_VIRTADDR_IS_VALID(sbi) \ + ) ? TRUE : FALSE) + +#define AXFS_IS_REGION_INCORE(_region) \ + (((_region)->incore > 0) ? TRUE : FALSE) + +static inline int AXFS_IS_REGION_XIP(struct axfs_super *sbi, struct axfs_region_desc *region) +{ + if(!axfs_can_xip(sbi) || !AXFS_IS_REGION_MMAPABLE(sbi,region) || AXFS_IS_REGION_COMPRESSED(region) || AXFS_IS_REGION_INCORE(region)) + return FALSE; + + return TRUE; +} + +#define AXFS_GET_XIP_REGION_PHYSADDR(sbi) \ + (unsigned long)((sbi)->phys_start_addr + (sbi)->xip.fsoffset) + +#define AXFS_GET_INODE_NAME(sbi,inode_index) \ + (char *)( \ + (sbi)->strings.virt_addr \ + + AXFS_GET_INODE_NAME_OFFSET(sbi,inode_index) \ + ) + +#define AXFS_GET_CBLOCK_ADDRESS(sbi, cnode_index)\ + (unsigned long)( \ + (sbi)->compressed.virt_addr \ + + AXFS_GET_CBLOCK_OFFSET(sbi, cnode_index) \ + ) + +#define AXFS_GET_NODE_ADDRESS(sbi,node__index) \ + (unsigned long)( \ + (sbi)->node_index.virt_addr \ + + AXFS_GET_NODE_INDEX(sbi, node__index) \ + ) + +#define AXFS_GET_BANODE_ADDRESS(sbi,banode_index) \ + (unsigned long)( \ + (sbi)->byte_aligned.virt_addr \ + + AXFS_GET_BANODE_OFFSET(sbi, banode_index) \ + ) + +#define AXFS_FSOFFSET_2_DEVOFFSET(sbi,fsoffset) \ + (( \ + ((sbi)->phys_start_addr == 0) && ((sbi)->virt_start_addr == 0) \ + ) ? (fsoffset) : (fsoffset - (sbi)->mmap_size) \ + ) + +#define AXFS_GET_CBLOCK_LENGTH(sbi,cblock_index) \ + (u64)( \ + (u64)AXFS_GET_CBLOCK_OFFSET(sbi, ((u64)(cblock_index)+(u64)1)) \ + - (u64)AXFS_GET_CBLOCK_OFFSET(sbi, (cblock_index)) \ + ) + +#endif