This is the main filesystem logic.

Signed-off-by: Jared Hulbert <[EMAIL PROTECTED]>
---
diff --git a/fs/axfs/axfs_inode.c b/fs/axfs/axfs_inode.c
new file mode 100644
index 0000000..cbf3dd1
--- /dev/null
+++ b/fs/axfs/axfs_inode.c
@@ -0,0 +1,488 @@
+/*
+ * 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 <[EMAIL PROTECTED]>
+ *  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 <linux/axfs.h>
+#include <linux/pagemap.h>
+
+/***************** 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 *);
+static ssize_t axfs_file_read(struct file *, char __user *, size_t, loff_t *);
+static int axfs_readpage(struct file *, struct page *);
+static int axfs_fault(struct vm_area_struct *, struct vm_fault *);
+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 *);
+
+/******************************************************************************/
+
+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,
+       .aio_read = generic_file_aio_read,
+       .mmap = axfs_mmap,
+};
+
+static struct address_space_operations axfs_aops = {
+       .readpage = axfs_readpage,
+       .get_xip_mem = axfs_get_xip_mem,
+};
+
+static struct inode_operations axfs_dir_inode_operations = {
+       .lookup = axfs_lookup,
+};
+
+static struct vm_operations_struct axfs_vm_ops = {
+       .fault = axfs_fault,
+};
+
+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;
+       }
+}
+
+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;
+}
+
+struct inode *axfs_create_vfs_inode(struct super_block *sb, int ino)
+{
+       struct axfs_super *sbi = AXFS_SB(sb);
+       struct inode *inode;
+       u64 size;
+
+       inode = iget5_locked(sb, ino, axfs_iget5_test, axfs_iget5_set, &ino);
+
+       if (!(inode && (inode->i_state & I_NEW)))
+               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);
+
+       inode->i_mtime = inode->i_atime = inode->i_ctime = sbi->timestamp;
+       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;
+               init_special_inode(inode, inode->i_mode, old_decode_dev(size));
+       }
+       unlock_new_inode(inode);
+
+       return inode;
+}
+
+
+static int axfs_mmap(struct file *file, struct vm_area_struct *vma)
+{
+
+       file_accessed(file);
+
+       vma->vm_ops = &axfs_vm_ops;
+
+       vma->vm_flags |= VM_CAN_NONLINEAR | VM_MIXEDMAP;
+
+       return 0;
+}
+
+static struct dentry *axfs_lookup(struct inode *dir, struct dentry *dentry,
+                                 struct nameidata *nd)
+{
+       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;
+}
+
+/******************************************************************************
+ *
+ * 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)
+{
+       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);
+       u64 ino_number = inode->i_ino;
+       u64 array_index;
+
+       array_index = AXFS_GET_INODE_ARRAY_INDEX(sbi, ino_number) + vmf->pgoff;
+
+       /* 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);
+
+       /* figure out if the node is XIP or compressed and call the
+          appropriate function
+        */
+       if (AXFS_IS_NODE_XIP(sbi, array_index))
+               return xip_file_fault(vma, vmf);
+       return filemap_fault(vma, vmf);
+
+}
+
+
+/******************************************************************************
+ *
+ * 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)
+{
+       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)) {
+                       read = xip_file_read(filp, buf, readlength, ppos);
+               } else {
+                       read = do_sync_read(filp, buf, readlength, ppos);
+               }
+               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);
+               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;
+               }
+               downgrade_write(&sbi->lock);
+               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;
+}
+
+static int axfs_get_xip_mem(struct address_space *mapping, pgoff_t offset,
+                           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;
+}
+


--
To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to