12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2da4458bdSDavid Howells /* NOMMU mmap support for RomFS on MTD devices
3da4458bdSDavid Howells *
4da4458bdSDavid Howells * Copyright © 2007 Red Hat, Inc. All Rights Reserved.
5da4458bdSDavid Howells * Written by David Howells (dhowells@redhat.com)
6da4458bdSDavid Howells */
7da4458bdSDavid Howells
8da4458bdSDavid Howells #include <linux/mm.h>
9da4458bdSDavid Howells #include <linux/mtd/super.h>
10da4458bdSDavid Howells #include "internal.h"
11da4458bdSDavid Howells
12da4458bdSDavid Howells /*
13da4458bdSDavid Howells * try to determine where a shared mapping can be made
14da4458bdSDavid Howells * - only supported for NOMMU at the moment (MMU can't doesn't copy private
15da4458bdSDavid Howells * mappings)
16da4458bdSDavid Howells * - attempts to map through to the underlying MTD device
17da4458bdSDavid Howells */
romfs_get_unmapped_area(struct file * file,unsigned long addr,unsigned long len,unsigned long pgoff,unsigned long flags)18da4458bdSDavid Howells static unsigned long romfs_get_unmapped_area(struct file *file,
19da4458bdSDavid Howells unsigned long addr,
20da4458bdSDavid Howells unsigned long len,
21da4458bdSDavid Howells unsigned long pgoff,
22da4458bdSDavid Howells unsigned long flags)
23da4458bdSDavid Howells {
24da4458bdSDavid Howells struct inode *inode = file->f_mapping->host;
25da4458bdSDavid Howells struct mtd_info *mtd = inode->i_sb->s_mtd;
262b4b2482SBob Liu unsigned long isize, offset, maxpages, lpages;
274991e725SArtem Bityutskiy int ret;
28da4458bdSDavid Howells
29da4458bdSDavid Howells if (!mtd)
304991e725SArtem Bityutskiy return (unsigned long) -ENOSYS;
31da4458bdSDavid Howells
322b4b2482SBob Liu /* the mapping mustn't extend beyond the EOF */
332b4b2482SBob Liu lpages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
34da4458bdSDavid Howells isize = i_size_read(inode);
35da4458bdSDavid Howells offset = pgoff << PAGE_SHIFT;
362b4b2482SBob Liu
372b4b2482SBob Liu maxpages = (isize + PAGE_SIZE - 1) >> PAGE_SHIFT;
382b4b2482SBob Liu if ((pgoff >= maxpages) || (maxpages - pgoff < lpages))
39da4458bdSDavid Howells return (unsigned long) -EINVAL;
40da4458bdSDavid Howells
41da4458bdSDavid Howells if (addr != 0)
42da4458bdSDavid Howells return (unsigned long) -EINVAL;
43da4458bdSDavid Howells
44da4458bdSDavid Howells if (len > mtd->size || pgoff >= (mtd->size >> PAGE_SHIFT))
45da4458bdSDavid Howells return (unsigned long) -EINVAL;
46da4458bdSDavid Howells
47da4458bdSDavid Howells offset += ROMFS_I(inode)->i_dataoffset;
48e4ba4fc2SGreg Ungerer if (offset >= mtd->size)
49da4458bdSDavid Howells return (unsigned long) -EINVAL;
50e4ba4fc2SGreg Ungerer /* the mapping mustn't extend beyond the EOF */
51e4ba4fc2SGreg Ungerer if ((offset + len) > mtd->size)
52e4ba4fc2SGreg Ungerer len = mtd->size - offset;
53da4458bdSDavid Howells
544991e725SArtem Bityutskiy ret = mtd_get_unmapped_area(mtd, len, offset, flags);
554991e725SArtem Bityutskiy if (ret == -EOPNOTSUPP)
564991e725SArtem Bityutskiy ret = -ENOSYS;
574991e725SArtem Bityutskiy return (unsigned long) ret;
58da4458bdSDavid Howells }
59da4458bdSDavid Howells
60da4458bdSDavid Howells /*
61da4458bdSDavid Howells * permit a R/O mapping to be made directly through onto an MTD device if
62da4458bdSDavid Howells * possible
63da4458bdSDavid Howells */
romfs_mmap(struct file * file,struct vm_area_struct * vma)64da4458bdSDavid Howells static int romfs_mmap(struct file *file, struct vm_area_struct *vma)
65da4458bdSDavid Howells {
66fc4f4be9SDavid Hildenbrand return is_nommu_shared_mapping(vma->vm_flags) ? 0 : -ENOSYS;
67da4458bdSDavid Howells }
68da4458bdSDavid Howells
romfs_mmap_capabilities(struct file * file)69b4caecd4SChristoph Hellwig static unsigned romfs_mmap_capabilities(struct file *file)
70b4caecd4SChristoph Hellwig {
71b4caecd4SChristoph Hellwig struct mtd_info *mtd = file_inode(file)->i_sb->s_mtd;
72b4caecd4SChristoph Hellwig
73b4caecd4SChristoph Hellwig if (!mtd)
74b4caecd4SChristoph Hellwig return NOMMU_MAP_COPY;
75b4caecd4SChristoph Hellwig return mtd_mmap_capabilities(mtd);
76b4caecd4SChristoph Hellwig }
77b4caecd4SChristoph Hellwig
78da4458bdSDavid Howells const struct file_operations romfs_ro_fops = {
79da4458bdSDavid Howells .llseek = generic_file_llseek,
80aad4f8bbSAl Viro .read_iter = generic_file_read_iter,
81*2cb1e089SDavid Howells .splice_read = filemap_splice_read,
82da4458bdSDavid Howells .mmap = romfs_mmap,
83da4458bdSDavid Howells .get_unmapped_area = romfs_get_unmapped_area,
84b4caecd4SChristoph Hellwig .mmap_capabilities = romfs_mmap_capabilities,
85da4458bdSDavid Howells };
86