Release 4.7 fs/ramfs/file-nommu.c
/* file-nommu.c: no-MMU version of ramfs
*
* Copyright (C) 2005 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/module.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/highmem.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/backing-dev.h>
#include <linux/ramfs.h>
#include <linux/pagevec.h>
#include <linux/mman.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include "internal.h"
static int ramfs_nommu_setattr(struct dentry *, struct iattr *);
static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
unsigned long addr,
unsigned long len,
unsigned long pgoff,
unsigned long flags);
static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma);
static unsigned ramfs_mmap_capabilities(struct file *file)
{
return NOMMU_MAP_DIRECT | NOMMU_MAP_COPY | NOMMU_MAP_READ |
NOMMU_MAP_WRITE | NOMMU_MAP_EXEC;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
christoph hellwig | christoph hellwig | 22 | 100.00% | 1 | 100.00% |
| Total | 22 | 100.00% | 1 | 100.00% |
const struct file_operations ramfs_file_operations = {
.mmap_capabilities = ramfs_mmap_capabilities,
.mmap = ramfs_nommu_mmap,
.get_unmapped_area = ramfs_nommu_get_unmapped_area,
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
.fsync = noop_fsync,
.splice_read = generic_file_splice_read,
.splice_write = iter_file_splice_write,
.llseek = generic_file_llseek,
};
const struct inode_operations ramfs_file_inode_operations = {
.setattr = ramfs_nommu_setattr,
.getattr = simple_getattr,
};
/*****************************************************************************/
/*
* add a contiguous set of pages into a ramfs inode when it's truncated from
* size 0 on the assumption that it's going to be used for an mmap of shared
* memory
*/
int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
{
unsigned long npages, xpages, loop;
struct page *pages;
unsigned order;
void *data;
int ret;
gfp_t gfp = mapping_gfp_mask(inode->i_mapping);
/* make various checks */
order = get_order(newsize);
if (unlikely(order >= MAX_ORDER))
return -EFBIG;
ret = inode_newsize_ok(inode, newsize);
if (ret)
return ret;
i_size_write(inode, newsize);
/* allocate enough contiguous pages to be able to satisfy the
* request */
pages = alloc_pages(gfp, order);
if (!pages)
return -ENOMEM;
/* split the high-order page into an array of single pages */
xpages = 1UL << order;
npages = (newsize + PAGE_SIZE - 1) >> PAGE_SHIFT;
split_page(pages, order);
/* trim off any pages we don't actually require */
for (loop = npages; loop < xpages; loop++)
__free_page(pages + loop);
/* clear the memory we allocated */
newsize = PAGE_SIZE * npages;
data = page_address(pages);
memset(data, 0, newsize);
/* attach all the pages to the inode's address space */
for (loop = 0; loop < npages; loop++) {
struct page *page = pages + loop;
ret = add_to_page_cache_lru(page, inode->i_mapping, loop,
gfp);
if (ret < 0)
goto add_error;
/* prevent the page from being discarded on memory pressure */
SetPageDirty(page);
SetPageUptodate(page);
unlock_page(page);
put_page(page);
}
return 0;
add_error:
while (loop < npages)
__free_page(pages + loop++);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
david howells | david howells | 221 | 81.55% | 1 | 12.50% |
nick piggin | nick piggin | 17 | 6.27% | 2 | 25.00% |
michal hocko | michal hocko | 12 | 4.43% | 1 | 12.50% |
bob liu | bob liu | 10 | 3.69% | 2 | 25.00% |
enrik berkhan | enrik berkhan | 6 | 2.21% | 1 | 12.50% |
johannes weiner | johannes weiner | 5 | 1.85% | 1 | 12.50% |
| Total | 271 | 100.00% | 8 | 100.00% |
/*****************************************************************************/
/*
*
*/
static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size)
{
int ret;
/* assume a truncate from zero size is going to be for the purposes of
* shared mmap */
if (size == 0) {
if (unlikely(newsize >> 32))
return -EFBIG;
return ramfs_nommu_expand_for_mapping(inode, newsize);
}
/* check that a decrease in size doesn't cut off any shared mappings */
if (newsize < size) {
ret = nommu_shrink_inode_mappings(inode, size, newsize);
if (ret < 0)
return ret;
}
truncate_setsize(inode, newsize);
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
david howells | david howells | 86 | 96.63% | 2 | 50.00% |
christoph hellwig | christoph hellwig | 2 | 2.25% | 1 | 25.00% |
bryan wu | bryan wu | 1 | 1.12% | 1 | 25.00% |
| Total | 89 | 100.00% | 4 | 100.00% |
/*****************************************************************************/
/*
* handle a change of attributes
* - we're specifically interested in a change of size
*/
static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
{
struct inode *inode = d_inode(dentry);
unsigned int old_ia_valid = ia->ia_valid;
int ret = 0;
/* POSIX UID/GID verification for setting inode attributes */
ret = inode_change_ok(inode, ia);
if (ret)
return ret;
/* pick out size-changing events */
if (ia->ia_valid & ATTR_SIZE) {
loff_t size = inode->i_size;
if (ia->ia_size != size) {
ret = ramfs_nommu_resize(inode, ia->ia_size, size);
if (ret < 0 || ia->ia_valid == ATTR_SIZE)
goto out;
} else {
/* we skipped the truncate but must still update
* timestamps
*/
ia->ia_valid |= ATTR_MTIME|ATTR_CTIME;
}
}
setattr_copy(inode, ia);
out:
ia->ia_valid = old_ia_valid;
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
david howells | david howells | 122 | 85.92% | 2 | 40.00% |
bryan wu | bryan wu | 17 | 11.97% | 1 | 20.00% |
nick piggin | nick piggin | 2 | 1.41% | 1 | 20.00% |
christoph hellwig | christoph hellwig | 1 | 0.70% | 1 | 20.00% |
| Total | 142 | 100.00% | 5 | 100.00% |
/*****************************************************************************/
/*
* try to determine where a shared mapping can be made
* - we require that:
* - the pages to be mapped must exist
* - the pages be physically contiguous in sequence
*/
static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags)
{
unsigned long maxpages, lpages, nr, loop, ret;
struct inode *inode = file_inode(file);
struct page **pages = NULL, **ptr, *page;
loff_t isize;
/* the mapping mustn't extend beyond the EOF */
lpages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
isize = i_size_read(inode);
ret = -ENOSYS;
maxpages = (isize + PAGE_SIZE - 1) >> PAGE_SHIFT;
if (pgoff >= maxpages)
goto out;
if (maxpages - pgoff < lpages)
goto out;
/* gang-find the pages */
pages = kcalloc(lpages, sizeof(struct page *), GFP_KERNEL);
if (!pages)
goto out_free;
nr = find_get_pages(inode->i_mapping, pgoff, lpages, pages);
if (nr != lpages)
goto out_free_pages; /* leave if some pages were missing */
/* check the pages for physical adjacency */
ptr = pages;
page = *ptr++;
page++;
for (loop = lpages; loop > 1; loop--)
if (*ptr++ != page++)
goto out_free_pages;
/* okay - all conditions fulfilled */
ret = (unsigned long) page_address(pages[0]);
out_free_pages:
ptr = pages;
for (loop = nr; loop > 0; loop--)
put_page(*ptr++);
out_free:
kfree(pages);
out:
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
david howells | david howells | 260 | 97.38% | 2 | 33.33% |
al viro | al viro | 3 | 1.12% | 1 | 16.67% |
fabian frederick | fabian frederick | 2 | 0.75% | 1 | 16.67% |
rich felker | rich felker | 1 | 0.37% | 1 | 16.67% |
axel lin | axel lin | 1 | 0.37% | 1 | 16.67% |
| Total | 267 | 100.00% | 6 | 100.00% |
/*****************************************************************************/
/*
* set up a mapping for shared memory segments
*/
static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma)
{
if (!(vma->vm_flags & (VM_SHARED | VM_MAYSHARE)))
return -ENOSYS;
file_accessed(file);
vma->vm_ops = &generic_file_vm_ops;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
david howells | david howells | 45 | 90.00% | 3 | 60.00% |
rich felker | rich felker | 4 | 8.00% | 1 | 20.00% |
axel lin | axel lin | 1 | 2.00% | 1 | 20.00% |
| Total | 50 | 100.00% | 5 | 100.00% |
Overall Contributors
| Person | Tokens | Prop | Commits | CommitProp |
david howells | david howells | 842 | 82.47% | 6 | 17.14% |
axel lin | axel lin | 44 | 4.31% | 1 | 2.86% |
christoph hellwig | christoph hellwig | 31 | 3.04% | 4 | 11.43% |
nick piggin | nick piggin | 19 | 1.86% | 3 | 8.57% |
bryan wu | bryan wu | 18 | 1.76% | 2 | 5.71% |
michal hocko | michal hocko | 12 | 1.18% | 1 | 2.86% |
bob liu | bob liu | 10 | 0.98% | 2 | 5.71% |
al viro | al viro | 8 | 0.78% | 4 | 11.43% |
enrik berkhan | enrik berkhan | 6 | 0.59% | 1 | 2.86% |
johannes weiner | johannes weiner | 5 | 0.49% | 1 | 2.86% |
rich felker | rich felker | 5 | 0.49% | 1 | 2.86% |
octavian purdila | octavian purdila | 4 | 0.39% | 1 | 2.86% |
dimitri gorokhovik | dimitri gorokhovik | 3 | 0.29% | 1 | 2.86% |
tejun heo | tejun heo | 3 | 0.29% | 1 | 2.86% |
catalin marinas | catalin marinas | 3 | 0.29% | 1 | 2.86% |
jens axboe | jens axboe | 2 | 0.20% | 1 | 2.86% |
badari pulavarty | badari pulavarty | 2 | 0.20% | 1 | 2.86% |
arjan van de ven | arjan van de ven | 2 | 0.20% | 2 | 5.71% |
fabian frederick | fabian frederick | 2 | 0.20% | 1 | 2.86% |
| Total | 1021 | 100.00% | 35 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.