Commit 16a100190d39592d1d56ff5a0b978b20288c3427
Committed by
Linus Torvalds
1 parent
1ae7000630
Exists in
master
and in
7 other branches
[PATCH] holepunch: fix disconnected pages after second truncate
shmem_truncate_range has its own truncate_inode_pages_range, to free any pages racily instantiated while it was in progress: a SHMEM_PAGEIN flag is set when this might have happened. But holepunching gets no chance to clear that flag at the start of vmtruncate_range, so it's always set (unless a truncate came just before), so holepunch almost always does this second truncate_inode_pages_range. shmem holepunch has unlikely swap<->file races hereabouts whatever we do (without a fuller rework than is fit for this release): I was going to skip the second truncate in the punch_hole case, but Miklos points out that would make holepunch correctness more vulnerable to swapoff. So keep the second truncate, but follow it by an unmap_mapping_range to eliminate the disconnected pages (freed from pagecache while still mapped in userspace) that it might have left behind. Signed-off-by: Hugh Dickins <hugh@veritas.com> Cc: Miklos Szeredi <mszeredi@suse.cz> Cc: Badari Pulavarty <pbadari@us.ibm.com> Cc: Nick Piggin <npiggin@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 8 additions and 0 deletions Side-by-side Diff
mm/shmem.c
... | ... | @@ -674,8 +674,16 @@ |
674 | 674 | * generic_delete_inode did it, before we lowered next_index. |
675 | 675 | * Also, though shmem_getpage checks i_size before adding to |
676 | 676 | * cache, no recheck after: so fix the narrow window there too. |
677 | + * | |
678 | + * Recalling truncate_inode_pages_range and unmap_mapping_range | |
679 | + * every time for punch_hole (which never got a chance to clear | |
680 | + * SHMEM_PAGEIN at the start of vmtruncate_range) is expensive, | |
681 | + * yet hardly ever necessary: try to optimize them out later. | |
677 | 682 | */ |
678 | 683 | truncate_inode_pages_range(inode->i_mapping, start, end); |
684 | + if (punch_hole) | |
685 | + unmap_mapping_range(inode->i_mapping, start, | |
686 | + end - start, 1); | |
679 | 687 | } |
680 | 688 | |
681 | 689 | spin_lock(&info->lock); |