diff options
Diffstat (limited to 'mm/shmem.c')
| -rw-r--r-- | mm/shmem.c | 106 |
1 files changed, 65 insertions, 41 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index e2a6ae1a44e9..04fb4f1ab88e 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); |
| @@ -1261,7 +1265,7 @@ repeat: | |||
| 1261 | } | 1265 | } |
| 1262 | 1266 | ||
| 1263 | /* We have to do this with page locked to prevent races */ | 1267 | /* We have to do this with page locked to prevent races */ |
| 1264 | if (TestSetPageLocked(swappage)) { | 1268 | if (!trylock_page(swappage)) { |
| 1265 | shmem_swp_unmap(entry); | 1269 | shmem_swp_unmap(entry); |
| 1266 | spin_unlock(&info->lock); | 1270 | spin_unlock(&info->lock); |
| 1267 | wait_on_page_locked(swappage); | 1271 | wait_on_page_locked(swappage); |
| @@ -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,24 +1315,21 @@ 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) { |
| 1328 | shmem_swp_unmap(entry); | 1329 | shmem_swp_unmap(entry); |
| 1329 | filepage = find_get_page(mapping, idx); | 1330 | filepage = find_get_page(mapping, idx); |
| 1330 | if (filepage && | 1331 | if (filepage && |
| 1331 | (!PageUptodate(filepage) || TestSetPageLocked(filepage))) { | 1332 | (!PageUptodate(filepage) || !trylock_page(filepage))) { |
| 1332 | spin_unlock(&info->lock); | 1333 | spin_unlock(&info->lock); |
| 1333 | wait_on_page_locked(filepage); | 1334 | wait_on_page_locked(filepage); |
| 1334 | page_cache_release(filepage); | 1335 | page_cache_release(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 | ||
| @@ -1503,7 +1513,6 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
| 1503 | inode->i_uid = current->fsuid; | 1513 | inode->i_uid = current->fsuid; |
| 1504 | inode->i_gid = current->fsgid; | 1514 | inode->i_gid = current->fsgid; |
| 1505 | inode->i_blocks = 0; | 1515 | inode->i_blocks = 0; |
| 1506 | inode->i_mapping->a_ops = &shmem_aops; | ||
| 1507 | inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; | 1516 | inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; |
| 1508 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 1517 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
| 1509 | inode->i_generation = get_seconds(); | 1518 | inode->i_generation = get_seconds(); |
| @@ -1518,6 +1527,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
| 1518 | init_special_inode(inode, mode, dev); | 1527 | init_special_inode(inode, mode, dev); |
| 1519 | break; | 1528 | break; |
| 1520 | case S_IFREG: | 1529 | case S_IFREG: |
| 1530 | inode->i_mapping->a_ops = &shmem_aops; | ||
| 1521 | inode->i_op = &shmem_inode_operations; | 1531 | inode->i_op = &shmem_inode_operations; |
| 1522 | inode->i_fop = &shmem_file_operations; | 1532 | inode->i_fop = &shmem_file_operations; |
| 1523 | mpol_shared_policy_init(&info->policy, | 1533 | mpol_shared_policy_init(&info->policy, |
| @@ -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) |
| @@ -1907,6 +1929,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s | |||
| 1907 | return error; | 1929 | return error; |
| 1908 | } | 1930 | } |
| 1909 | unlock_page(page); | 1931 | unlock_page(page); |
| 1932 | inode->i_mapping->a_ops = &shmem_aops; | ||
| 1910 | inode->i_op = &shmem_symlink_inode_operations; | 1933 | inode->i_op = &shmem_symlink_inode_operations; |
| 1911 | kaddr = kmap_atomic(page, KM_USER0); | 1934 | kaddr = kmap_atomic(page, KM_USER0); |
| 1912 | memcpy(kaddr, symname, len); | 1935 | memcpy(kaddr, symname, len); |
| @@ -2330,7 +2353,7 @@ static void shmem_destroy_inode(struct inode *inode) | |||
| 2330 | kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); | 2353 | kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); |
| 2331 | } | 2354 | } |
| 2332 | 2355 | ||
| 2333 | static void init_once(struct kmem_cache *cachep, void *foo) | 2356 | static void init_once(void *foo) |
| 2334 | { | 2357 | { |
| 2335 | struct shmem_inode_info *p = (struct shmem_inode_info *) foo; | 2358 | struct shmem_inode_info *p = (struct shmem_inode_info *) foo; |
| 2336 | 2359 | ||
| @@ -2369,8 +2392,9 @@ static const struct file_operations shmem_file_operations = { | |||
| 2369 | .mmap = shmem_mmap, | 2392 | .mmap = shmem_mmap, |
| 2370 | #ifdef CONFIG_TMPFS | 2393 | #ifdef CONFIG_TMPFS |
| 2371 | .llseek = generic_file_llseek, | 2394 | .llseek = generic_file_llseek, |
| 2372 | .read = shmem_file_read, | 2395 | .read = do_sync_read, |
| 2373 | .write = do_sync_write, | 2396 | .write = do_sync_write, |
| 2397 | .aio_read = shmem_file_aio_read, | ||
| 2374 | .aio_write = generic_file_aio_write, | 2398 | .aio_write = generic_file_aio_write, |
| 2375 | .fsync = simple_sync_file, | 2399 | .fsync = simple_sync_file, |
| 2376 | .splice_read = generic_file_splice_read, | 2400 | .splice_read = generic_file_splice_read, |
