diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/shmem.c | 31 |
1 files changed, 20 insertions, 11 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 8fa27e4e582a..262d71173447 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -1039,6 +1039,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) | |||
1039 | struct address_space *mapping; | 1039 | struct address_space *mapping; |
1040 | unsigned long index; | 1040 | unsigned long index; |
1041 | struct inode *inode; | 1041 | struct inode *inode; |
1042 | bool unlock_mutex = false; | ||
1042 | 1043 | ||
1043 | BUG_ON(!PageLocked(page)); | 1044 | BUG_ON(!PageLocked(page)); |
1044 | mapping = page->mapping; | 1045 | mapping = page->mapping; |
@@ -1064,7 +1065,26 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) | |||
1064 | else | 1065 | else |
1065 | swap.val = 0; | 1066 | swap.val = 0; |
1066 | 1067 | ||
1068 | /* | ||
1069 | * Add inode to shmem_unuse()'s list of swapped-out inodes, | ||
1070 | * if it's not already there. Do it now because we cannot take | ||
1071 | * mutex while holding spinlock, and must do so before the page | ||
1072 | * is moved to swap cache, when its pagelock no longer protects | ||
1073 | * the inode from eviction. But don't unlock the mutex until | ||
1074 | * we've taken the spinlock, because shmem_unuse_inode() will | ||
1075 | * prune a !swapped inode from the swaplist under both locks. | ||
1076 | */ | ||
1077 | if (swap.val && list_empty(&info->swaplist)) { | ||
1078 | mutex_lock(&shmem_swaplist_mutex); | ||
1079 | /* move instead of add in case we're racing */ | ||
1080 | list_move_tail(&info->swaplist, &shmem_swaplist); | ||
1081 | unlock_mutex = true; | ||
1082 | } | ||
1083 | |||
1067 | spin_lock(&info->lock); | 1084 | spin_lock(&info->lock); |
1085 | if (unlock_mutex) | ||
1086 | mutex_unlock(&shmem_swaplist_mutex); | ||
1087 | |||
1068 | if (index >= info->next_index) { | 1088 | if (index >= info->next_index) { |
1069 | BUG_ON(!(info->flags & SHMEM_TRUNCATE)); | 1089 | BUG_ON(!(info->flags & SHMEM_TRUNCATE)); |
1070 | goto unlock; | 1090 | goto unlock; |
@@ -1084,21 +1104,10 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) | |||
1084 | delete_from_page_cache(page); | 1104 | delete_from_page_cache(page); |
1085 | shmem_swp_set(info, entry, swap.val); | 1105 | shmem_swp_set(info, entry, swap.val); |
1086 | shmem_swp_unmap(entry); | 1106 | shmem_swp_unmap(entry); |
1087 | if (list_empty(&info->swaplist)) | ||
1088 | inode = igrab(inode); | ||
1089 | else | ||
1090 | inode = NULL; | ||
1091 | spin_unlock(&info->lock); | 1107 | spin_unlock(&info->lock); |
1092 | swap_shmem_alloc(swap); | 1108 | swap_shmem_alloc(swap); |
1093 | BUG_ON(page_mapped(page)); | 1109 | BUG_ON(page_mapped(page)); |
1094 | swap_writepage(page, wbc); | 1110 | swap_writepage(page, wbc); |
1095 | if (inode) { | ||
1096 | mutex_lock(&shmem_swaplist_mutex); | ||
1097 | /* move instead of add in case we're racing */ | ||
1098 | list_move_tail(&info->swaplist, &shmem_swaplist); | ||
1099 | mutex_unlock(&shmem_swaplist_mutex); | ||
1100 | iput(inode); | ||
1101 | } | ||
1102 | return 0; | 1111 | return 0; |
1103 | } | 1112 | } |
1104 | 1113 | ||