aboutsummaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c196
1 files changed, 60 insertions, 136 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index a15a466d0d1d..bd106361be4b 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -264,46 +264,55 @@ static int shmem_radix_tree_replace(struct address_space *mapping,
264} 264}
265 265
266/* 266/*
267 * Sometimes, before we decide whether to proceed or to fail, we must check
268 * that an entry was not already brought back from swap by a racing thread.
269 *
270 * Checking page is not enough: by the time a SwapCache page is locked, it
271 * might be reused, and again be SwapCache, using the same swap as before.
272 */
273static bool shmem_confirm_swap(struct address_space *mapping,
274 pgoff_t index, swp_entry_t swap)
275{
276 void *item;
277
278 rcu_read_lock();
279 item = radix_tree_lookup(&mapping->page_tree, index);
280 rcu_read_unlock();
281 return item == swp_to_radix_entry(swap);
282}
283
284/*
267 * Like add_to_page_cache_locked, but error if expected item has gone. 285 * Like add_to_page_cache_locked, but error if expected item has gone.
268 */ 286 */
269static int shmem_add_to_page_cache(struct page *page, 287static int shmem_add_to_page_cache(struct page *page,
270 struct address_space *mapping, 288 struct address_space *mapping,
271 pgoff_t index, gfp_t gfp, void *expected) 289 pgoff_t index, gfp_t gfp, void *expected)
272{ 290{
273 int error = 0; 291 int error;
274 292
275 VM_BUG_ON(!PageLocked(page)); 293 VM_BUG_ON(!PageLocked(page));
276 VM_BUG_ON(!PageSwapBacked(page)); 294 VM_BUG_ON(!PageSwapBacked(page));
277 295
296 page_cache_get(page);
297 page->mapping = mapping;
298 page->index = index;
299
300 spin_lock_irq(&mapping->tree_lock);
278 if (!expected) 301 if (!expected)
279 error = radix_tree_preload(gfp & GFP_RECLAIM_MASK); 302 error = radix_tree_insert(&mapping->page_tree, index, page);
303 else
304 error = shmem_radix_tree_replace(mapping, index, expected,
305 page);
280 if (!error) { 306 if (!error) {
281 page_cache_get(page); 307 mapping->nrpages++;
282 page->mapping = mapping; 308 __inc_zone_page_state(page, NR_FILE_PAGES);
283 page->index = index; 309 __inc_zone_page_state(page, NR_SHMEM);
284 310 spin_unlock_irq(&mapping->tree_lock);
285 spin_lock_irq(&mapping->tree_lock); 311 } else {
286 if (!expected) 312 page->mapping = NULL;
287 error = radix_tree_insert(&mapping->page_tree, 313 spin_unlock_irq(&mapping->tree_lock);
288 index, page); 314 page_cache_release(page);
289 else
290 error = shmem_radix_tree_replace(mapping, index,
291 expected, page);
292 if (!error) {
293 mapping->nrpages++;
294 __inc_zone_page_state(page, NR_FILE_PAGES);
295 __inc_zone_page_state(page, NR_SHMEM);
296 spin_unlock_irq(&mapping->tree_lock);
297 } else {
298 page->mapping = NULL;
299 spin_unlock_irq(&mapping->tree_lock);
300 page_cache_release(page);
301 }
302 if (!expected)
303 radix_tree_preload_end();
304 } 315 }
305 if (error)
306 mem_cgroup_uncharge_cache_page(page);
307 return error; 316 return error;
308} 317}
309 318
@@ -1124,9 +1133,9 @@ repeat:
1124 /* We have to do this with page locked to prevent races */ 1133 /* We have to do this with page locked to prevent races */
1125 lock_page(page); 1134 lock_page(page);
1126 if (!PageSwapCache(page) || page_private(page) != swap.val || 1135 if (!PageSwapCache(page) || page_private(page) != swap.val ||
1127 page->mapping) { 1136 !shmem_confirm_swap(mapping, index, swap)) {
1128 error = -EEXIST; /* try again */ 1137 error = -EEXIST; /* try again */
1129 goto failed; 1138 goto unlock;
1130 } 1139 }
1131 if (!PageUptodate(page)) { 1140 if (!PageUptodate(page)) {
1132 error = -EIO; 1141 error = -EIO;
@@ -1142,9 +1151,12 @@ repeat:
1142 1151
1143 error = mem_cgroup_cache_charge(page, current->mm, 1152 error = mem_cgroup_cache_charge(page, current->mm,
1144 gfp & GFP_RECLAIM_MASK); 1153 gfp & GFP_RECLAIM_MASK);
1145 if (!error) 1154 if (!error) {
1146 error = shmem_add_to_page_cache(page, mapping, index, 1155 error = shmem_add_to_page_cache(page, mapping, index,
1147 gfp, swp_to_radix_entry(swap)); 1156 gfp, swp_to_radix_entry(swap));
1157 /* We already confirmed swap, and make no allocation */
1158 VM_BUG_ON(error);
1159 }
1148 if (error) 1160 if (error)
1149 goto failed; 1161 goto failed;
1150 1162
@@ -1181,11 +1193,18 @@ repeat:
1181 __set_page_locked(page); 1193 __set_page_locked(page);
1182 error = mem_cgroup_cache_charge(page, current->mm, 1194 error = mem_cgroup_cache_charge(page, current->mm,
1183 gfp & GFP_RECLAIM_MASK); 1195 gfp & GFP_RECLAIM_MASK);
1184 if (!error)
1185 error = shmem_add_to_page_cache(page, mapping, index,
1186 gfp, NULL);
1187 if (error) 1196 if (error)
1188 goto decused; 1197 goto decused;
1198 error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
1199 if (!error) {
1200 error = shmem_add_to_page_cache(page, mapping, index,
1201 gfp, NULL);
1202 radix_tree_preload_end();
1203 }
1204 if (error) {
1205 mem_cgroup_uncharge_cache_page(page);
1206 goto decused;
1207 }
1189 lru_cache_add_anon(page); 1208 lru_cache_add_anon(page);
1190 1209
1191 spin_lock(&info->lock); 1210 spin_lock(&info->lock);
@@ -1245,14 +1264,10 @@ decused:
1245unacct: 1264unacct:
1246 shmem_unacct_blocks(info->flags, 1); 1265 shmem_unacct_blocks(info->flags, 1);
1247failed: 1266failed:
1248 if (swap.val && error != -EINVAL) { 1267 if (swap.val && error != -EINVAL &&
1249 struct page *test = find_get_page(mapping, index); 1268 !shmem_confirm_swap(mapping, index, swap))
1250 if (test && !radix_tree_exceptional_entry(test)) 1269 error = -EEXIST;
1251 page_cache_release(test); 1270unlock:
1252 /* Have another try if the entry has changed */
1253 if (test != swp_to_radix_entry(swap))
1254 error = -EEXIST;
1255 }
1256 if (page) { 1271 if (page) {
1257 unlock_page(page); 1272 unlock_page(page);
1258 page_cache_release(page); 1273 page_cache_release(page);
@@ -1264,7 +1279,7 @@ failed:
1264 spin_unlock(&info->lock); 1279 spin_unlock(&info->lock);
1265 goto repeat; 1280 goto repeat;
1266 } 1281 }
1267 if (error == -EEXIST) 1282 if (error == -EEXIST) /* from above or from radix_tree_insert */
1268 goto repeat; 1283 goto repeat;
1269 return error; 1284 return error;
1270} 1285}
@@ -1594,6 +1609,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
1594 struct splice_pipe_desc spd = { 1609 struct splice_pipe_desc spd = {
1595 .pages = pages, 1610 .pages = pages,
1596 .partial = partial, 1611 .partial = partial,
1612 .nr_pages_max = PIPE_DEF_BUFFERS,
1597 .flags = flags, 1613 .flags = flags,
1598 .ops = &page_cache_pipe_buf_ops, 1614 .ops = &page_cache_pipe_buf_ops,
1599 .spd_release = spd_release_page, 1615 .spd_release = spd_release_page,
@@ -1682,7 +1698,7 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
1682 if (spd.nr_pages) 1698 if (spd.nr_pages)
1683 error = splice_to_pipe(pipe, &spd); 1699 error = splice_to_pipe(pipe, &spd);
1684 1700
1685 splice_shrink_spd(pipe, &spd); 1701 splice_shrink_spd(&spd);
1686 1702
1687 if (error > 0) { 1703 if (error > 0) {
1688 *ppos += error; 1704 *ppos += error;
@@ -1691,98 +1707,6 @@ static ssize_t shmem_file_splice_read(struct file *in, loff_t *ppos,
1691 return error; 1707 return error;
1692} 1708}
1693 1709
1694/*
1695 * llseek SEEK_DATA or SEEK_HOLE through the radix_tree.
1696 */
1697static pgoff_t shmem_seek_hole_data(struct address_space *mapping,
1698 pgoff_t index, pgoff_t end, int origin)
1699{
1700 struct page *page;
1701 struct pagevec pvec;
1702 pgoff_t indices[PAGEVEC_SIZE];
1703 bool done = false;
1704 int i;
1705
1706 pagevec_init(&pvec, 0);
1707 pvec.nr = 1; /* start small: we may be there already */
1708 while (!done) {
1709 pvec.nr = shmem_find_get_pages_and_swap(mapping, index,
1710 pvec.nr, pvec.pages, indices);
1711 if (!pvec.nr) {
1712 if (origin == SEEK_DATA)
1713 index = end;
1714 break;
1715 }
1716 for (i = 0; i < pvec.nr; i++, index++) {
1717 if (index < indices[i]) {
1718 if (origin == SEEK_HOLE) {
1719 done = true;
1720 break;
1721 }
1722 index = indices[i];
1723 }
1724 page = pvec.pages[i];
1725 if (page && !radix_tree_exceptional_entry(page)) {
1726 if (!PageUptodate(page))
1727 page = NULL;
1728 }
1729 if (index >= end ||
1730 (page && origin == SEEK_DATA) ||
1731 (!page && origin == SEEK_HOLE)) {
1732 done = true;
1733 break;
1734 }
1735 }
1736 shmem_deswap_pagevec(&pvec);
1737 pagevec_release(&pvec);
1738 pvec.nr = PAGEVEC_SIZE;
1739 cond_resched();
1740 }
1741 return index;
1742}
1743
1744static loff_t shmem_file_llseek(struct file *file, loff_t offset, int origin)
1745{
1746 struct address_space *mapping;
1747 struct inode *inode;
1748 pgoff_t start, end;
1749 loff_t new_offset;
1750
1751 if (origin != SEEK_DATA && origin != SEEK_HOLE)
1752 return generic_file_llseek_size(file, offset, origin,
1753 MAX_LFS_FILESIZE);
1754 mapping = file->f_mapping;
1755 inode = mapping->host;
1756 mutex_lock(&inode->i_mutex);
1757 /* We're holding i_mutex so we can access i_size directly */
1758
1759 if (offset < 0)
1760 offset = -EINVAL;
1761 else if (offset >= inode->i_size)
1762 offset = -ENXIO;
1763 else {
1764 start = offset >> PAGE_CACHE_SHIFT;
1765 end = (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
1766 new_offset = shmem_seek_hole_data(mapping, start, end, origin);
1767 new_offset <<= PAGE_CACHE_SHIFT;
1768 if (new_offset > offset) {
1769 if (new_offset < inode->i_size)
1770 offset = new_offset;
1771 else if (origin == SEEK_DATA)
1772 offset = -ENXIO;
1773 else
1774 offset = inode->i_size;
1775 }
1776 }
1777
1778 if (offset >= 0 && offset != file->f_pos) {
1779 file->f_pos = offset;
1780 file->f_version = 0;
1781 }
1782 mutex_unlock(&inode->i_mutex);
1783 return offset;
1784}
1785
1786static long shmem_fallocate(struct file *file, int mode, loff_t offset, 1710static long shmem_fallocate(struct file *file, int mode, loff_t offset,
1787 loff_t len) 1711 loff_t len)
1788{ 1712{
@@ -2786,7 +2710,7 @@ static const struct address_space_operations shmem_aops = {
2786static const struct file_operations shmem_file_operations = { 2710static const struct file_operations shmem_file_operations = {
2787 .mmap = shmem_mmap, 2711 .mmap = shmem_mmap,
2788#ifdef CONFIG_TMPFS 2712#ifdef CONFIG_TMPFS
2789 .llseek = shmem_file_llseek, 2713 .llseek = generic_file_llseek,
2790 .read = do_sync_read, 2714 .read = do_sync_read,
2791 .write = do_sync_write, 2715 .write = do_sync_write,
2792 .aio_read = shmem_file_aio_read, 2716 .aio_read = shmem_file_aio_read,