Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 179363
b: refs/heads/master
c: 7e66087
h: refs/heads/master
i:
  179361: c8fbe2c
  179359: 8686443
v: v3
  • Loading branch information
David Howells authored and Linus Torvalds committed Jan 16, 2010
1 parent 14bc544 commit 4f14f7a
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 31 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 81759b5b221107488bda99fe7beeb7b734f61133
refs/heads/master: 7e6608724c640924aad1d556d17df33ebaa6124d
31 changes: 1 addition & 30 deletions trunk/fs/ramfs/file-nommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,35 +121,6 @@ int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize)
return ret;
}

/*****************************************************************************/
/*
* check that file shrinkage doesn't leave any VMAs dangling in midair
*/
static int ramfs_nommu_check_mappings(struct inode *inode,
size_t newsize, size_t size)
{
struct vm_area_struct *vma;
struct prio_tree_iter iter;

down_write(&nommu_region_sem);

/* search for VMAs that fall within the dead zone */
vma_prio_tree_foreach(vma, &iter, &inode->i_mapping->i_mmap,
newsize >> PAGE_SHIFT,
(size + PAGE_SIZE - 1) >> PAGE_SHIFT
) {
/* found one - only interested if it's shared out of the page
* cache */
if (vma->vm_flags & VM_SHARED) {
up_write(&nommu_region_sem);
return -ETXTBSY; /* not quite true, but near enough */
}
}

up_write(&nommu_region_sem);
return 0;
}

/*****************************************************************************/
/*
*
Expand All @@ -169,7 +140,7 @@ static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size)

/* check that a decrease in size doesn't cut off any shared mappings */
if (newsize < size) {
ret = ramfs_nommu_check_mappings(inode, newsize, size);
ret = nommu_shrink_inode_mappings(inode, size, newsize);
if (ret < 0)
return ret;
}
Expand Down
1 change: 1 addition & 0 deletions trunk/include/linux/mm.h
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,7 @@ extern void zone_pcp_update(struct zone *zone);

/* nommu.c */
extern atomic_long_t mmap_pages_allocated;
extern int nommu_shrink_inode_mappings(struct inode *, size_t, size_t);

/* prio_tree.c */
void vma_prio_tree_add(struct vm_area_struct *, struct vm_area_struct *old);
Expand Down
62 changes: 62 additions & 0 deletions trunk/mm/nommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1914,3 +1914,65 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
mmput(mm);
return len;
}

/**
* nommu_shrink_inode_mappings - Shrink the shared mappings on an inode
* @inode: The inode to check
* @size: The current filesize of the inode
* @newsize: The proposed filesize of the inode
*
* Check the shared mappings on an inode on behalf of a shrinking truncate to
* make sure that that any outstanding VMAs aren't broken and then shrink the
* vm_regions that extend that beyond so that do_mmap_pgoff() doesn't
* automatically grant mappings that are too large.
*/
int nommu_shrink_inode_mappings(struct inode *inode, size_t size,
size_t newsize)
{
struct vm_area_struct *vma;
struct prio_tree_iter iter;
struct vm_region *region;
pgoff_t low, high;
size_t r_size, r_top;

low = newsize >> PAGE_SHIFT;
high = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;

down_write(&nommu_region_sem);

/* search for VMAs that fall within the dead zone */
vma_prio_tree_foreach(vma, &iter, &inode->i_mapping->i_mmap,
low, high) {
/* found one - only interested if it's shared out of the page
* cache */
if (vma->vm_flags & VM_SHARED) {
up_write(&nommu_region_sem);
return -ETXTBSY; /* not quite true, but near enough */
}
}

/* reduce any regions that overlap the dead zone - if in existence,
* these will be pointed to by VMAs that don't overlap the dead zone
*
* we don't check for any regions that start beyond the EOF as there
* shouldn't be any
*/
vma_prio_tree_foreach(vma, &iter, &inode->i_mapping->i_mmap,
0, ULONG_MAX) {
if (!(vma->vm_flags & VM_SHARED))
continue;

region = vma->vm_region;
r_size = region->vm_top - region->vm_start;
r_top = (region->vm_pgoff << PAGE_SHIFT) + r_size;

if (r_top > newsize) {
region->vm_top -= r_top - newsize;
if (region->vm_end > region->vm_top)
region->vm_end = region->vm_top;
}
}

up_write(&nommu_region_sem);
return 0;
}

0 comments on commit 4f14f7a

Please sign in to comment.