|
@@ -1039,6 +1039,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
|
|
|
struct address_space *mapping;
|
|
|
unsigned long index;
|
|
|
struct inode *inode;
|
|
|
+ bool unlock_mutex = false;
|
|
|
|
|
|
BUG_ON(!PageLocked(page));
|
|
|
mapping = page->mapping;
|
|
@@ -1064,7 +1065,26 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
|
|
|
else
|
|
|
swap.val = 0;
|
|
|
|
|
|
+ /*
|
|
|
+ * Add inode to shmem_unuse()'s list of swapped-out inodes,
|
|
|
+ * if it's not already there. Do it now because we cannot take
|
|
|
+ * mutex while holding spinlock, and must do so before the page
|
|
|
+ * is moved to swap cache, when its pagelock no longer protects
|
|
|
+ * the inode from eviction. But don't unlock the mutex until
|
|
|
+ * we've taken the spinlock, because shmem_unuse_inode() will
|
|
|
+ * prune a !swapped inode from the swaplist under both locks.
|
|
|
+ */
|
|
|
+ if (swap.val && list_empty(&info->swaplist)) {
|
|
|
+ mutex_lock(&shmem_swaplist_mutex);
|
|
|
+ /* move instead of add in case we're racing */
|
|
|
+ list_move_tail(&info->swaplist, &shmem_swaplist);
|
|
|
+ unlock_mutex = true;
|
|
|
+ }
|
|
|
+
|
|
|
spin_lock(&info->lock);
|
|
|
+ if (unlock_mutex)
|
|
|
+ mutex_unlock(&shmem_swaplist_mutex);
|
|
|
+
|
|
|
if (index >= info->next_index) {
|
|
|
BUG_ON(!(info->flags & SHMEM_TRUNCATE));
|
|
|
goto unlock;
|
|
@@ -1084,21 +1104,10 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
|
|
|
delete_from_page_cache(page);
|
|
|
shmem_swp_set(info, entry, swap.val);
|
|
|
shmem_swp_unmap(entry);
|
|
|
- if (list_empty(&info->swaplist))
|
|
|
- inode = igrab(inode);
|
|
|
- else
|
|
|
- inode = NULL;
|
|
|
spin_unlock(&info->lock);
|
|
|
swap_shmem_alloc(swap);
|
|
|
BUG_ON(page_mapped(page));
|
|
|
swap_writepage(page, wbc);
|
|
|
- if (inode) {
|
|
|
- mutex_lock(&shmem_swaplist_mutex);
|
|
|
- /* move instead of add in case we're racing */
|
|
|
- list_move_tail(&info->swaplist, &shmem_swaplist);
|
|
|
- mutex_unlock(&shmem_swaplist_mutex);
|
|
|
- iput(inode);
|
|
|
- }
|
|
|
return 0;
|
|
|
}
|
|
|
|