From 686e9e7248fedeaf5874c9d1ee1690458cb3e9ac Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 21 Oct 2003 18:20:16 -0700 Subject: [PATCH] [PATCH] tmpfs 4/7 getpage/truncate race fix From: Hugh Dickins Extend use of that SHMEM_PAGEIN flag to where shmem_getpage adds a page to the cache. It couldn't have caused a BUG_ON(inode->i_blocks), but if i_size is reduced (from another cpu) the instant after shmem_swp_alloc checks it, shmem_getpage could insert a page into the cache just after truncate_inode_pages has passed through cleaning it, leaving stale data (which may mysteriously reappear if the file is later extended). Easily fixed for tmpfs, using the mechanism just added for swapoff; and probably more important there, since its read from swap can insert non-0 data. But is there not a similar issue, a tiny window, in filemap.c? if truncate_inode_pages comes in between checking i_size and adding new page to cache. Not worth getting excited, but something to beware of. --- mm/shmem.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mm/shmem.c b/mm/shmem.c index 573430c7f7e5b..724ed5427e5a6 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -52,7 +52,7 @@ #define VM_ACCT(size) (PAGE_CACHE_ALIGN(size) >> PAGE_SHIFT) -/* info->flags needs a VM_flag to handle swapoff/truncate races efficiently */ +/* info->flags needs a VM_flag to handle pagein/truncate races efficiently */ #define SHMEM_PAGEIN VM_READ /* Pretend that each entry is of this size in directory's i_size */ @@ -498,6 +498,8 @@ done2: * Call truncate_inode_pages again: racing shmem_unuse_inode * may have swizzled a page in from swap since vmtruncate or * generic_delete_inode did it, before we lowered next_index. + * Also, though shmem_getpage checks i_size before adding to + * cache, no recheck after: so fix the narrow window there too. */ spin_unlock(&info->lock); truncate_inode_pages(inode->i_mapping, inode->i_size); @@ -863,6 +865,7 @@ repeat: swap_free(swap); } else if (!(error = move_from_swap_cache( swappage, idx, mapping))) { + info->flags |= SHMEM_PAGEIN; shmem_swp_set(info, entry, 0); shmem_swp_unmap(entry); spin_unlock(&info->lock); @@ -932,6 +935,7 @@ repeat: goto failed; goto repeat; } + info->flags |= SHMEM_PAGEIN; } info->alloced++; -- 2.53.0