| From ltsi-dev-bounces@lists.linuxfoundation.org Sat May 12 10:17:49 2012 |
| From: Marco Stornelli <marco.stornelli@gmail.com> |
| Date: Sat, 12 May 2012 19:11:14 +0200 |
| Subject: pramfs: xip support |
| To: LTSI <ltsi-dev@lists.linuxfoundation.org> |
| Message-ID: <4FAE99B2.1050508@gmail.com> |
| |
| |
| From: Marco Stornelli <marco.stornelli@gmail.com> |
| |
| XIP operations. |
| |
| Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com> |
| |
| --- |
| fs/pramfs/xip.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| fs/pramfs/xip.h | 33 +++++++++++++++ |
| mm/filemap_xip.c | 3 - |
| 3 files changed, 152 insertions(+), 1 deletion(-) |
| |
| --- /dev/null |
| +++ b/fs/pramfs/xip.c |
| @@ -0,0 +1,117 @@ |
| +/* |
| + * BRIEF DESCRIPTION |
| + * |
| + * XIP operations. |
| + * |
| + * Copyright 2009-2011 Marco Stornelli <marco.stornelli@gmail.com> |
| + * This file is licensed under the terms of the GNU General Public |
| + * License version 2. This program is licensed "as is" without any |
| + * warranty of any kind, whether express or implied. |
| + */ |
| + |
| +#include <linux/mm.h> |
| +#include <linux/fs.h> |
| +#include <linux/buffer_head.h> |
| +#include "pram.h" |
| +#include "xip.h" |
| + |
| +/* |
| + * Wrappers. We need to use the rcu read lock to avoid |
| + * concurrent truncate operation. No problem for write because we held |
| + * i_mutex. |
| + */ |
| +ssize_t pram_xip_file_read(struct file *filp, char __user *buf, |
| + size_t len, loff_t *ppos) |
| +{ |
| + ssize_t res; |
| + rcu_read_lock(); |
| + res = xip_file_read(filp, buf, len, ppos); |
| + rcu_read_unlock(); |
| + return res; |
| +} |
| + |
| +static int pram_xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
| +{ |
| + int ret = 0; |
| + rcu_read_lock(); |
| + ret = xip_file_fault(vma, vmf); |
| + rcu_read_unlock(); |
| + return ret; |
| +} |
| + |
| +static const struct vm_operations_struct pram_xip_vm_ops = { |
| + .fault = pram_xip_file_fault, |
| +}; |
| + |
| +int pram_xip_file_mmap(struct file * file, struct vm_area_struct * vma) |
| +{ |
| + BUG_ON(!file->f_mapping->a_ops->get_xip_mem); |
| + |
| + file_accessed(file); |
| + vma->vm_ops = &pram_xip_vm_ops; |
| + vma->vm_flags |= VM_CAN_NONLINEAR | VM_MIXEDMAP; |
| + return 0; |
| +} |
| + |
| +static int pram_find_and_alloc_blocks(struct inode *inode, sector_t iblock, |
| + sector_t *data_block, int create) |
| +{ |
| + int err = -EIO; |
| + u64 block; |
| + |
| + block = pram_find_data_block(inode, iblock); |
| + |
| + if (!block) { |
| + if (!create) { |
| + err = -ENODATA; |
| + goto err; |
| + } |
| + |
| + err = pram_alloc_blocks(inode, iblock, 1); |
| + if (err) |
| + goto err; |
| + |
| + block = pram_find_data_block(inode, iblock); |
| + if (!block) { |
| + err = -ENODATA; |
| + goto err; |
| + } |
| + } |
| + |
| + *data_block = block; |
| + err = 0; |
| + |
| + err: |
| + return err; |
| +} |
| + |
| +static inline int __pram_get_block(struct inode *inode, pgoff_t pgoff, |
| + int create, sector_t *result) |
| +{ |
| + int rc = 0; |
| + |
| + rc = pram_find_and_alloc_blocks(inode, (sector_t)pgoff, result, create); |
| + |
| + if (rc == -ENODATA) |
| + BUG_ON(create); |
| + |
| + return rc; |
| +} |
| + |
| +int pram_get_xip_mem(struct address_space *mapping, pgoff_t pgoff, int create, |
| + void **kmem, unsigned long *pfn) |
| +{ |
| + int rc; |
| + sector_t block = 0; |
| + |
| + /* first, retrieve the block */ |
| + rc = __pram_get_block(mapping->host, pgoff, create, &block); |
| + if (rc) |
| + goto exit; |
| + |
| + *kmem = pram_get_block(mapping->host->i_sb, block); |
| + *pfn = pram_get_pfn(mapping->host->i_sb, block); |
| + |
| +exit: |
| + return rc; |
| +} |
| --- /dev/null |
| +++ b/fs/pramfs/xip.h |
| @@ -0,0 +1,33 @@ |
| +/* |
| + * BRIEF DESCRIPTION |
| + * |
| + * XIP operations. |
| + * |
| + * Copyright 2009-2011 Marco Stornelli <marco.stornelli@gmail.com> |
| + * This file is licensed under the terms of the GNU General Public |
| + * License version 2. This program is licensed "as is" without any |
| + * warranty of any kind, whether express or implied. |
| + */ |
| + |
| +#ifdef CONFIG_PRAMFS_XIP |
| +int pram_get_xip_mem(struct address_space *, pgoff_t, int, void **, |
| + unsigned long *); |
| +ssize_t pram_xip_file_read(struct file *filp, char __user *buf, |
| + size_t len, loff_t *ppos); |
| +int pram_xip_file_mmap(struct file * file, struct vm_area_struct * vma); |
| +static inline int pram_use_xip(struct super_block *sb) |
| +{ |
| + struct pram_sb_info *sbi = PRAM_SB(sb); |
| + return sbi->s_mount_opt & PRAM_MOUNT_XIP; |
| +} |
| +#define mapping_is_xip(map) (map->a_ops->get_xip_mem) |
| + |
| +#else |
| + |
| +#define mapping_is_xip(map) 0 |
| +#define pram_use_xip(sb) 0 |
| +#define pram_get_xip_mem NULL |
| +#define pram_xip_file_read NULL |
| +#define pram_xip_file_mmap NULL |
| + |
| +#endif |
| --- a/mm/filemap_xip.c |
| +++ b/mm/filemap_xip.c |
| @@ -218,7 +218,7 @@ retry: |
| * |
| * This function is derived from filemap_fault, but used for execute in place |
| */ |
| -static int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
| +int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
| { |
| struct file *file = vma->vm_file; |
| struct address_space *mapping = file->f_mapping; |
| @@ -302,6 +302,7 @@ out: |
| } |
| } |
| |
| +EXPORT_SYMBOL_GPL(xip_file_fault); |
| static const struct vm_operations_struct xip_file_vm_ops = { |
| .fault = xip_file_fault, |
| }; |