Commit 6673fd3d authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] tmpfs 5/7 writepage/truncate race fix

From: Hugh Dickins <hugh@veritas.com>

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.
parent 686e9e72
...@@ -52,8 +52,9 @@ ...@@ -52,8 +52,9 @@
#define VM_ACCT(size) (PAGE_CACHE_ALIGN(size) >> PAGE_SHIFT) #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_PAGEIN VM_READ
#define SHMEM_TRUNCATE VM_WRITE
/* Pretend that each entry is of this size in directory's i_size */ /* Pretend that each entry is of this size in directory's i_size */
#define BOGO_DIRENT_SIZE 20 #define BOGO_DIRENT_SIZE 20
...@@ -393,6 +394,7 @@ static void shmem_truncate(struct inode *inode) ...@@ -393,6 +394,7 @@ static void shmem_truncate(struct inode *inode)
return; return;
spin_lock(&info->lock); spin_lock(&info->lock);
info->flags |= SHMEM_TRUNCATE;
limit = info->next_index; limit = info->next_index;
info->next_index = idx; info->next_index = idx;
if (info->swapped && idx < SHMEM_NR_DIRECT) { if (info->swapped && idx < SHMEM_NR_DIRECT) {
...@@ -505,6 +507,7 @@ static void shmem_truncate(struct inode *inode) ...@@ -505,6 +507,7 @@ static void shmem_truncate(struct inode *inode)
truncate_inode_pages(inode->i_mapping, inode->i_size); truncate_inode_pages(inode->i_mapping, inode->i_size);
spin_lock(&info->lock); spin_lock(&info->lock);
} }
info->flags &= ~SHMEM_TRUNCATE;
shmem_recalc_inode(inode); shmem_recalc_inode(inode);
spin_unlock(&info->lock); spin_unlock(&info->lock);
} }
...@@ -730,7 +733,10 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) ...@@ -730,7 +733,10 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
spin_lock(&info->lock); spin_lock(&info->lock);
shmem_recalc_inode(inode); 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); entry = shmem_swp_entry(info, index, NULL);
BUG_ON(!entry); BUG_ON(!entry);
BUG_ON(entry->val); BUG_ON(entry->val);
...@@ -744,6 +750,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) ...@@ -744,6 +750,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
} }
shmem_swp_unmap(entry); shmem_swp_unmap(entry);
unlock:
spin_unlock(&info->lock); spin_unlock(&info->lock);
swap_free(swap); swap_free(swap);
redirty: redirty:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment