// SPDX-License-Identifier: GPL-2.0-or-later /* file-nommu.c: no-MMU version of ramfs * * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
/*****************************************************************************/ /* * 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)
{ unsignedlong 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_PAGE_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);
/* 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;
}
/*****************************************************************************/ /* * handle a change of attributes * - we're specifically interested in a change of size
*/ staticint ramfs_nommu_setattr(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *ia)
{ struct inode *inode = d_inode(dentry); unsignedint old_ia_valid = ia->ia_valid; int ret = 0;
/* POSIX UID/GID verification for setting inode attributes */
ret = setattr_prepare(&nop_mnt_idmap, dentry, 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;
}
}
/*****************************************************************************/ /* * 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
*/ staticunsignedlong ramfs_nommu_get_unmapped_area(struct file *file, unsignedlong addr, unsignedlong len, unsignedlong pgoff, unsignedlong flags)
{ unsignedlong maxpages, lpages, nr_folios, loop, ret, nr_pages, pfn; struct inode *inode = file_inode(file); struct folio_batch fbatch;
loff_t isize;
/*****************************************************************************/ /* * set up a mapping for shared memory segments
*/ staticint ramfs_nommu_mmap_prepare(struct vm_area_desc *desc)
{ if (!is_nommu_shared_mapping(desc->vm_flags)) return -ENOSYS;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.