2009-02-12 13:40:10 +03:00
/* NOMMU mmap support for RomFS on MTD devices
*
* Copyright © 2007 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*
* 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 .
*/
# include <linux/mm.h>
# include <linux/mtd/super.h>
# include "internal.h"
/*
* try to determine where a shared mapping can be made
* - only supported for NOMMU at the moment ( MMU can ' t doesn ' t copy private
* mappings )
* - attempts to map through to the underlying MTD device
*/
static unsigned long romfs_get_unmapped_area ( struct file * file ,
unsigned long addr ,
unsigned long len ,
unsigned long pgoff ,
unsigned long flags )
{
struct inode * inode = file - > f_mapping - > host ;
struct mtd_info * mtd = inode - > i_sb - > s_mtd ;
2011-06-28 03:18:06 +04:00
unsigned long isize , offset , maxpages , lpages ;
2011-12-28 19:08:03 +04:00
int ret ;
2009-02-12 13:40:10 +03:00
if ( ! mtd )
2011-12-28 19:08:03 +04:00
return ( unsigned long ) - ENOSYS ;
2009-02-12 13:40:10 +03:00
2011-06-28 03:18:06 +04:00
/* the mapping mustn't extend beyond the EOF */
lpages = ( len + PAGE_SIZE - 1 ) > > PAGE_SHIFT ;
2009-02-12 13:40:10 +03:00
isize = i_size_read ( inode ) ;
offset = pgoff < < PAGE_SHIFT ;
2011-06-28 03:18:06 +04:00
maxpages = ( isize + PAGE_SIZE - 1 ) > > PAGE_SHIFT ;
if ( ( pgoff > = maxpages ) | | ( maxpages - pgoff < lpages ) )
2009-02-12 13:40:10 +03:00
return ( unsigned long ) - EINVAL ;
2011-12-28 19:08:03 +04:00
if ( addr ! = 0 )
return ( unsigned long ) - EINVAL ;
2009-02-12 13:40:10 +03:00
2011-12-28 19:08:03 +04:00
if ( len > mtd - > size | | pgoff > = ( mtd - > size > > PAGE_SHIFT ) )
return ( unsigned long ) - EINVAL ;
2009-02-12 13:40:10 +03:00
2011-12-28 19:08:03 +04:00
offset + = ROMFS_I ( inode ) - > i_dataoffset ;
2013-04-02 08:25:33 +04:00
if ( offset > = mtd - > size )
2011-12-28 19:08:03 +04:00
return ( unsigned long ) - EINVAL ;
2013-04-02 08:25:33 +04:00
/* the mapping mustn't extend beyond the EOF */
if ( ( offset + len ) > mtd - > size )
len = mtd - > size - offset ;
2009-02-12 13:40:10 +03:00
2011-12-28 19:08:03 +04:00
ret = mtd_get_unmapped_area ( mtd , len , offset , flags ) ;
if ( ret = = - EOPNOTSUPP )
ret = - ENOSYS ;
return ( unsigned long ) ret ;
2009-02-12 13:40:10 +03:00
}
/*
* permit a R / O mapping to be made directly through onto an MTD device if
* possible
*/
static int romfs_mmap ( struct file * file , struct vm_area_struct * vma )
{
return vma - > vm_flags & ( VM_SHARED | VM_MAYSHARE ) ? 0 : - ENOSYS ;
}
2015-01-14 12:42:32 +03:00
static unsigned romfs_mmap_capabilities ( struct file * file )
{
struct mtd_info * mtd = file_inode ( file ) - > i_sb - > s_mtd ;
if ( ! mtd )
return NOMMU_MAP_COPY ;
return mtd_mmap_capabilities ( mtd ) ;
}
2009-02-12 13:40:10 +03:00
const struct file_operations romfs_ro_fops = {
. llseek = generic_file_llseek ,
2014-04-02 22:33:16 +04:00
. read_iter = generic_file_read_iter ,
2009-02-12 13:40:10 +03:00
. splice_read = generic_file_splice_read ,
. mmap = romfs_mmap ,
. get_unmapped_area = romfs_get_unmapped_area ,
2015-01-14 12:42:32 +03:00
. mmap_capabilities = romfs_mmap_capabilities ,
2009-02-12 13:40:10 +03:00
} ;