From: Hugh Dickins If it's possible for a tmpfs page beyond i_size to remain in cache until shmem_truncate repeats truncate_inode_pages, then shmem_writepage's BUG_ON(index >= info->next_index) cannot be completely safe. But it's a useful check in a fragile area, so retain it when not in shmem_truncate. 25-akpm/mm/shmem.c | 11 +++++++++-- 1 files changed, 9 insertions(+), 2 deletions(-) diff -puN mm/shmem.c~tmpfs-05-writepage-truncate-race mm/shmem.c --- 25/mm/shmem.c~tmpfs-05-writepage-truncate-race Wed Oct 15 12:18:54 2003 +++ 25-akpm/mm/shmem.c Wed Oct 15 12:18:54 2003 @@ -52,8 +52,9 @@ #define VM_ACCT(size) (PAGE_CACHE_ALIGN(size) >> PAGE_SHIFT) -/* info->flags needs a VM_flag to handle pagein/truncate races efficiently */ +/* info->flags needs VM_flags to handle pagein/truncate races efficiently */ #define SHMEM_PAGEIN VM_READ +#define SHMEM_TRUNCATE VM_WRITE /* Pretend that each entry is of this size in directory's i_size */ #define BOGO_DIRENT_SIZE 20 @@ -393,6 +394,7 @@ static void shmem_truncate(struct inode return; spin_lock(&info->lock); + info->flags |= SHMEM_TRUNCATE; limit = info->next_index; info->next_index = idx; if (info->swapped && idx < SHMEM_NR_DIRECT) { @@ -505,6 +507,7 @@ done2: truncate_inode_pages(inode->i_mapping, inode->i_size); spin_lock(&info->lock); } + info->flags &= ~SHMEM_TRUNCATE; shmem_recalc_inode(inode); spin_unlock(&info->lock); } @@ -730,7 +733,10 @@ static int shmem_writepage(struct page * spin_lock(&info->lock); shmem_recalc_inode(inode); - BUG_ON(index >= info->next_index); + if (index >= info->next_index) { + BUG_ON(!(info->flags & SHMEM_TRUNCATE)); + goto unlock; + } entry = shmem_swp_entry(info, index, NULL); BUG_ON(!entry); BUG_ON(entry->val); @@ -744,6 +750,7 @@ static int shmem_writepage(struct page * } shmem_swp_unmap(entry); +unlock: spin_unlock(&info->lock); swap_free(swap); redirty: _