diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 99 |
1 files changed, 61 insertions, 38 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index e2a6ae1a44e9..952d361774bb 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -922,20 +922,26 @@ found: | |||
922 | error = 1; | 922 | error = 1; |
923 | if (!inode) | 923 | if (!inode) |
924 | goto out; | 924 | goto out; |
925 | /* Precharge page while we can wait, compensate afterwards */ | 925 | /* Precharge page using GFP_KERNEL while we can wait */ |
926 | error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL); | 926 | error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL); |
927 | if (error) | 927 | if (error) |
928 | goto out; | 928 | goto out; |
929 | error = radix_tree_preload(GFP_KERNEL); | 929 | error = radix_tree_preload(GFP_KERNEL); |
930 | if (error) | 930 | if (error) { |
931 | goto uncharge; | 931 | mem_cgroup_uncharge_cache_page(page); |
932 | goto out; | ||
933 | } | ||
932 | error = 1; | 934 | error = 1; |
933 | 935 | ||
934 | spin_lock(&info->lock); | 936 | spin_lock(&info->lock); |
935 | ptr = shmem_swp_entry(info, idx, NULL); | 937 | ptr = shmem_swp_entry(info, idx, NULL); |
936 | if (ptr && ptr->val == entry.val) | 938 | if (ptr && ptr->val == entry.val) { |
937 | error = add_to_page_cache(page, inode->i_mapping, | 939 | error = add_to_page_cache_locked(page, inode->i_mapping, |
938 | idx, GFP_NOWAIT); | 940 | idx, GFP_NOWAIT); |
941 | /* does mem_cgroup_uncharge_cache_page on error */ | ||
942 | } else /* we must compensate for our precharge above */ | ||
943 | mem_cgroup_uncharge_cache_page(page); | ||
944 | |||
939 | if (error == -EEXIST) { | 945 | if (error == -EEXIST) { |
940 | struct page *filepage = find_get_page(inode->i_mapping, idx); | 946 | struct page *filepage = find_get_page(inode->i_mapping, idx); |
941 | error = 1; | 947 | error = 1; |
@@ -961,8 +967,6 @@ found: | |||
961 | shmem_swp_unmap(ptr); | 967 | shmem_swp_unmap(ptr); |
962 | spin_unlock(&info->lock); | 968 | spin_unlock(&info->lock); |
963 | radix_tree_preload_end(); | 969 | radix_tree_preload_end(); |
964 | uncharge: | ||
965 | mem_cgroup_uncharge_page(page); | ||
966 | out: | 970 | out: |
967 | unlock_page(page); | 971 | unlock_page(page); |
968 | page_cache_release(page); | 972 | page_cache_release(page); |
@@ -1297,8 +1301,8 @@ repeat: | |||
1297 | SetPageUptodate(filepage); | 1301 | SetPageUptodate(filepage); |
1298 | set_page_dirty(filepage); | 1302 | set_page_dirty(filepage); |
1299 | swap_free(swap); | 1303 | swap_free(swap); |
1300 | } else if (!(error = add_to_page_cache( | 1304 | } else if (!(error = add_to_page_cache_locked(swappage, mapping, |
1301 | swappage, mapping, idx, GFP_NOWAIT))) { | 1305 | idx, GFP_NOWAIT))) { |
1302 | info->flags |= SHMEM_PAGEIN; | 1306 | info->flags |= SHMEM_PAGEIN; |
1303 | shmem_swp_set(info, entry, 0); | 1307 | shmem_swp_set(info, entry, 0); |
1304 | shmem_swp_unmap(entry); | 1308 | shmem_swp_unmap(entry); |
@@ -1311,17 +1315,14 @@ repeat: | |||
1311 | shmem_swp_unmap(entry); | 1315 | shmem_swp_unmap(entry); |
1312 | spin_unlock(&info->lock); | 1316 | spin_unlock(&info->lock); |
1313 | unlock_page(swappage); | 1317 | unlock_page(swappage); |
1318 | page_cache_release(swappage); | ||
1314 | if (error == -ENOMEM) { | 1319 | if (error == -ENOMEM) { |
1315 | /* allow reclaim from this memory cgroup */ | 1320 | /* allow reclaim from this memory cgroup */ |
1316 | error = mem_cgroup_cache_charge(swappage, | 1321 | error = mem_cgroup_shrink_usage(current->mm, |
1317 | current->mm, gfp & ~__GFP_HIGHMEM); | 1322 | gfp); |
1318 | if (error) { | 1323 | if (error) |
1319 | page_cache_release(swappage); | ||
1320 | goto failed; | 1324 | goto failed; |
1321 | } | ||
1322 | mem_cgroup_uncharge_page(swappage); | ||
1323 | } | 1325 | } |
1324 | page_cache_release(swappage); | ||
1325 | goto repeat; | 1326 | goto repeat; |
1326 | } | 1327 | } |
1327 | } else if (sgp == SGP_READ && !filepage) { | 1328 | } else if (sgp == SGP_READ && !filepage) { |
@@ -1358,6 +1359,8 @@ repeat: | |||
1358 | } | 1359 | } |
1359 | 1360 | ||
1360 | if (!filepage) { | 1361 | if (!filepage) { |
1362 | int ret; | ||
1363 | |||
1361 | spin_unlock(&info->lock); | 1364 | spin_unlock(&info->lock); |
1362 | filepage = shmem_alloc_page(gfp, info, idx); | 1365 | filepage = shmem_alloc_page(gfp, info, idx); |
1363 | if (!filepage) { | 1366 | if (!filepage) { |
@@ -1386,10 +1389,18 @@ repeat: | |||
1386 | swap = *entry; | 1389 | swap = *entry; |
1387 | shmem_swp_unmap(entry); | 1390 | shmem_swp_unmap(entry); |
1388 | } | 1391 | } |
1389 | if (error || swap.val || 0 != add_to_page_cache_lru( | 1392 | ret = error || swap.val; |
1390 | filepage, mapping, idx, GFP_NOWAIT)) { | 1393 | if (ret) |
1394 | mem_cgroup_uncharge_cache_page(filepage); | ||
1395 | else | ||
1396 | ret = add_to_page_cache_lru(filepage, mapping, | ||
1397 | idx, GFP_NOWAIT); | ||
1398 | /* | ||
1399 | * At add_to_page_cache_lru() failure, uncharge will | ||
1400 | * be done automatically. | ||
1401 | */ | ||
1402 | if (ret) { | ||
1391 | spin_unlock(&info->lock); | 1403 | spin_unlock(&info->lock); |
1392 | mem_cgroup_uncharge_page(filepage); | ||
1393 | page_cache_release(filepage); | 1404 | page_cache_release(filepage); |
1394 | shmem_unacct_blocks(info->flags, 1); | 1405 | shmem_unacct_blocks(info->flags, 1); |
1395 | shmem_free_blocks(inode, 1); | 1406 | shmem_free_blocks(inode, 1); |
@@ -1398,7 +1409,6 @@ repeat: | |||
1398 | goto failed; | 1409 | goto failed; |
1399 | goto repeat; | 1410 | goto repeat; |
1400 | } | 1411 | } |
1401 | mem_cgroup_uncharge_page(filepage); | ||
1402 | info->flags |= SHMEM_PAGEIN; | 1412 | info->flags |= SHMEM_PAGEIN; |
1403 | } | 1413 | } |
1404 | 1414 | ||
@@ -1690,26 +1700,38 @@ static void do_shmem_file_read(struct file *filp, loff_t *ppos, read_descriptor_ | |||
1690 | file_accessed(filp); | 1700 | file_accessed(filp); |
1691 | } | 1701 | } |
1692 | 1702 | ||
1693 | static ssize_t shmem_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | 1703 | static ssize_t shmem_file_aio_read(struct kiocb *iocb, |
1704 | const struct iovec *iov, unsigned long nr_segs, loff_t pos) | ||
1694 | { | 1705 | { |
1695 | read_descriptor_t desc; | 1706 | struct file *filp = iocb->ki_filp; |
1707 | ssize_t retval; | ||
1708 | unsigned long seg; | ||
1709 | size_t count; | ||
1710 | loff_t *ppos = &iocb->ki_pos; | ||
1696 | 1711 | ||
1697 | if ((ssize_t) count < 0) | 1712 | retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE); |
1698 | return -EINVAL; | 1713 | if (retval) |
1699 | if (!access_ok(VERIFY_WRITE, buf, count)) | 1714 | return retval; |
1700 | return -EFAULT; | ||
1701 | if (!count) | ||
1702 | return 0; | ||
1703 | 1715 | ||
1704 | desc.written = 0; | 1716 | for (seg = 0; seg < nr_segs; seg++) { |
1705 | desc.count = count; | 1717 | read_descriptor_t desc; |
1706 | desc.arg.buf = buf; | ||
1707 | desc.error = 0; | ||
1708 | 1718 | ||
1709 | do_shmem_file_read(filp, ppos, &desc, file_read_actor); | 1719 | desc.written = 0; |
1710 | if (desc.written) | 1720 | desc.arg.buf = iov[seg].iov_base; |
1711 | return desc.written; | 1721 | desc.count = iov[seg].iov_len; |
1712 | return desc.error; | 1722 | if (desc.count == 0) |
1723 | continue; | ||
1724 | desc.error = 0; | ||
1725 | do_shmem_file_read(filp, ppos, &desc, file_read_actor); | ||
1726 | retval += desc.written; | ||
1727 | if (desc.error) { | ||
1728 | retval = retval ?: desc.error; | ||
1729 | break; | ||
1730 | } | ||
1731 | if (desc.count > 0) | ||
1732 | break; | ||
1733 | } | ||
1734 | return retval; | ||
1713 | } | 1735 | } |
1714 | 1736 | ||
1715 | static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf) | 1737 | static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf) |
@@ -2330,7 +2352,7 @@ static void shmem_destroy_inode(struct inode *inode) | |||
2330 | kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); | 2352 | kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); |
2331 | } | 2353 | } |
2332 | 2354 | ||
2333 | static void init_once(struct kmem_cache *cachep, void *foo) | 2355 | static void init_once(void *foo) |
2334 | { | 2356 | { |
2335 | struct shmem_inode_info *p = (struct shmem_inode_info *) foo; | 2357 | struct shmem_inode_info *p = (struct shmem_inode_info *) foo; |
2336 | 2358 | ||
@@ -2369,8 +2391,9 @@ static const struct file_operations shmem_file_operations = { | |||
2369 | .mmap = shmem_mmap, | 2391 | .mmap = shmem_mmap, |
2370 | #ifdef CONFIG_TMPFS | 2392 | #ifdef CONFIG_TMPFS |
2371 | .llseek = generic_file_llseek, | 2393 | .llseek = generic_file_llseek, |
2372 | .read = shmem_file_read, | 2394 | .read = do_sync_read, |
2373 | .write = do_sync_write, | 2395 | .write = do_sync_write, |
2396 | .aio_read = shmem_file_aio_read, | ||
2374 | .aio_write = generic_file_aio_write, | 2397 | .aio_write = generic_file_aio_write, |
2375 | .fsync = simple_sync_file, | 2398 | .fsync = simple_sync_file, |
2376 | .splice_read = generic_file_splice_read, | 2399 | .splice_read = generic_file_splice_read, |