[PATCH v3] mtd: mtdchar: allow mmap for ram devices in memory address space.

Brian Norris computersforpeace at gmail.com
Fri Nov 20 19:25:01 EST 2015


In case this gets resurrected...

On Fri, Mar 07, 2014 at 02:54:39PM +0100, Philippe De Muyter wrote:
> use mtd_get_unmapped_area, as asked by an ancient comment, to get
> the physical address (if any) in memory of the mtd device.
> 
> Therefore, mapram_unmapped_area had to be changed to return the physical
> address, not the virtual one, For the NOMMU case, that makes no difference,
> but for the MMU case, it is needed by mapram_unmapped_area to implement mmap.
> 
> Signed-off-by: Philippe De Muyter <phdm at macqel.be>
> Cc: David Howells <dhowells at redhat.com>
> Cc: Markus Niebel <Markus.Niebel at tqs.de>
> Cc: Brian Norris <computersforpeace at gmail.com>
> ---
> v3: avoid duplicating test done by mtd_get_unmapped_area
> 
>  drivers/mtd/chips/map_ram.c |    2 +-
>  drivers/mtd/mtdchar.c       |   24 ++++++++++--------------
>  2 files changed, 11 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
> index 991c2a1..e93d147 100644
> --- a/drivers/mtd/chips/map_ram.c
> +++ b/drivers/mtd/chips/map_ram.c
> @@ -92,7 +92,7 @@ static unsigned long mapram_unmapped_area(struct mtd_info *mtd,
>  					  unsigned long flags)
>  {
>  	struct map_info *map = mtd->priv;
> -	return (unsigned long) map->virt + offset;
> +	return (unsigned long) map->phys + offset;
>  }
>  
>  static int mapram_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
> diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
> index 2147e73..5956246 100644
> --- a/drivers/mtd/mtdchar.c
> +++ b/drivers/mtd/mtdchar.c
> @@ -1112,20 +1112,16 @@ static int mtdchar_mmap(struct file *file, struct vm_area_struct *vma)
>  #ifdef CONFIG_MMU
>  	struct mtd_file_info *mfi = file->private_data;
>  	struct mtd_info *mtd = mfi->mtd;
> -	struct map_info *map = mtd->priv;
> -
> -        /* This is broken because it assumes the MTD device is map-based
> -	   and that mtd->priv is a valid struct map_info.  It should be
> -	   replaced with something that uses the mtd_get_unmapped_area()
> -	   operation properly. */
> -	if (0 /*mtd->type == MTD_RAM || mtd->type == MTD_ROM*/) {
> -#ifdef pgprot_noncached
> -		if (file->f_flags & O_DSYNC || map->phys >= __pa(high_memory))
> -			vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
> -#endif
> -		return vm_iomap_memory(vma, map->phys, map->size);
> -	}
> -	return -ENODEV;
> +	loff_t offset = vma->vm_pgoff << PAGE_SHIFT;
> +	loff_t len = vma->vm_end - vma->vm_start;
> +	phys_addr_t start;
> +
> +	start = mtd_get_unmapped_area(mtd, len, offset, vma->vm_flags);

Hmm, you're storing an 'unsigned long' in 'phys_addr_t', then treating
it as unsigned for the error checking. Is that guaranteed to work right?
Especially if sizeof(phys_addr_t) != sizeof(unsigned long)? e.g., if
phys_addr_t is 64 bits (with PAE?), but unsigned long is 32-bits, we
might see:

	start = mtd_get_unmapped_area(); // -EOPNOTSUPP

But -EOPNOTSUPP in a 32-bit unsigned long is only:

	0xffffffa1

which extends to:

	0x00000000ffffffa1

and doesn't match favorably with '-EOPNOTSUPP' when you compare it
later.

I think it makes more sense for 'start' to either match the return type
of mtd_get_unmapped_area() (i.e., unsigned long), or else just be a
signed type, so we don't have the unsigned/signed comparison issues
below.

Regards,
Brian

> +	if (start == -EOPNOTSUPP)
> +		return -ENODEV;
> +	if (start == -EINVAL)
> +		return -EINVAL;
> +	return vm_iomap_memory(vma, start, len);
>  #else
>  	return vma->vm_flags & VM_SHARED ? 0 : -EACCES;
>  #endif
> -- 
> 1.7.5.3
> 



More information about the linux-mtd mailing list