aboutsummaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
diff options
context:
space:
mode:
authorHugh Dickins <hughd@google.com>2011-07-25 20:12:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-25 23:57:11 -0400
commit27ab700626f048407e9466d389a43c7d3aa45967 (patch)
treea8d371d8a3727110310cba457840be0f2cfb77c6 /mm/shmem.c
parente83c32e8f92724a06a22a3b42f3afc07db93e131 (diff)
tmpfs: simplify filepage/swappage
We can now simplify shmem_getpage_gfp(): there is no longer a dilemma of filepage passed in via shmem_readpage(), then swappage found, which must then be copied over to it. Although at first it's tempting to replace the **pagep arg by returning struct page *, that makes a mess of IS_ERR_OR_NULL(page)s in all the callers, so leave as is. Insert BUG_ON(!PageUptodate) when we find and lock page: some of the complication came from uninitialized pages inserted into filecache prior to readpage; but now we're in control, and only release pagelock on filecache once it's uptodate (if an error occurs in reading back from swap, the page remains in swapcache, never moved to filecache). Signed-off-by: Hugh Dickins <hughd@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c237
1 files changed, 108 insertions, 129 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index 8f8534f35476..bf6e9c11d859 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1246,41 +1246,47 @@ static int shmem_getpage_gfp(struct inode *inode, pgoff_t idx,
1246 struct address_space *mapping = inode->i_mapping; 1246 struct address_space *mapping = inode->i_mapping;
1247 struct shmem_inode_info *info = SHMEM_I(inode); 1247 struct shmem_inode_info *info = SHMEM_I(inode);
1248 struct shmem_sb_info *sbinfo; 1248 struct shmem_sb_info *sbinfo;
1249 struct page *filepage; 1249 struct page *page;
1250 struct page *swappage;
1251 struct page *prealloc_page = NULL; 1250 struct page *prealloc_page = NULL;
1252 swp_entry_t *entry; 1251 swp_entry_t *entry;
1253 swp_entry_t swap; 1252 swp_entry_t swap;
1254 int error; 1253 int error;
1254 int ret;
1255 1255
1256 if (idx >= SHMEM_MAX_INDEX) 1256 if (idx >= SHMEM_MAX_INDEX)
1257 return -EFBIG; 1257 return -EFBIG;
1258repeat: 1258repeat:
1259 filepage = find_lock_page(mapping, idx); 1259 page = find_lock_page(mapping, idx);
1260 if (filepage && PageUptodate(filepage)) 1260 if (page) {
1261 goto done;
1262 if (!filepage) {
1263 /* 1261 /*
1264 * Try to preload while we can wait, to not make a habit of 1262 * Once we can get the page lock, it must be uptodate:
1265 * draining atomic reserves; but don't latch on to this cpu. 1263 * if there were an error in reading back from swap,
1264 * the page would not be inserted into the filecache.
1266 */ 1265 */
1267 error = radix_tree_preload(gfp & GFP_RECLAIM_MASK); 1266 BUG_ON(!PageUptodate(page));
1268 if (error) 1267 goto done;
1269 goto failed; 1268 }
1270 radix_tree_preload_end(); 1269
1271 if (sgp != SGP_READ && !prealloc_page) { 1270 /*
1272 prealloc_page = shmem_alloc_page(gfp, info, idx); 1271 * Try to preload while we can wait, to not make a habit of
1273 if (prealloc_page) { 1272 * draining atomic reserves; but don't latch on to this cpu.
1274 SetPageSwapBacked(prealloc_page); 1273 */
1275 if (mem_cgroup_cache_charge(prealloc_page, 1274 error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
1276 current->mm, GFP_KERNEL)) { 1275 if (error)
1277 page_cache_release(prealloc_page); 1276 goto out;
1278 prealloc_page = NULL; 1277 radix_tree_preload_end();
1279 } 1278
1279 if (sgp != SGP_READ && !prealloc_page) {
1280 prealloc_page = shmem_alloc_page(gfp, info, idx);
1281 if (prealloc_page) {
1282 SetPageSwapBacked(prealloc_page);
1283 if (mem_cgroup_cache_charge(prealloc_page,
1284 current->mm, GFP_KERNEL)) {
1285 page_cache_release(prealloc_page);
1286 prealloc_page = NULL;
1280 } 1287 }
1281 } 1288 }
1282 } 1289 }
1283 error = 0;
1284 1290
1285 spin_lock(&info->lock); 1291 spin_lock(&info->lock);
1286 shmem_recalc_inode(inode); 1292 shmem_recalc_inode(inode);
@@ -1288,21 +1294,21 @@ repeat:
1288 if (IS_ERR(entry)) { 1294 if (IS_ERR(entry)) {
1289 spin_unlock(&info->lock); 1295 spin_unlock(&info->lock);
1290 error = PTR_ERR(entry); 1296 error = PTR_ERR(entry);
1291 goto failed; 1297 goto out;
1292 } 1298 }
1293 swap = *entry; 1299 swap = *entry;
1294 1300
1295 if (swap.val) { 1301 if (swap.val) {
1296 /* Look it up and read it in.. */ 1302 /* Look it up and read it in.. */
1297 swappage = lookup_swap_cache(swap); 1303 page = lookup_swap_cache(swap);
1298 if (!swappage) { 1304 if (!page) {
1299 shmem_swp_unmap(entry); 1305 shmem_swp_unmap(entry);
1300 spin_unlock(&info->lock); 1306 spin_unlock(&info->lock);
1301 /* here we actually do the io */ 1307 /* here we actually do the io */
1302 if (fault_type) 1308 if (fault_type)
1303 *fault_type |= VM_FAULT_MAJOR; 1309 *fault_type |= VM_FAULT_MAJOR;
1304 swappage = shmem_swapin(swap, gfp, info, idx); 1310 page = shmem_swapin(swap, gfp, info, idx);
1305 if (!swappage) { 1311 if (!page) {
1306 spin_lock(&info->lock); 1312 spin_lock(&info->lock);
1307 entry = shmem_swp_alloc(info, idx, sgp, gfp); 1313 entry = shmem_swp_alloc(info, idx, sgp, gfp);
1308 if (IS_ERR(entry)) 1314 if (IS_ERR(entry))
@@ -1314,62 +1320,42 @@ repeat:
1314 } 1320 }
1315 spin_unlock(&info->lock); 1321 spin_unlock(&info->lock);
1316 if (error) 1322 if (error)
1317 goto failed; 1323 goto out;
1318 goto repeat; 1324 goto repeat;
1319 } 1325 }
1320 wait_on_page_locked(swappage); 1326 wait_on_page_locked(page);
1321 page_cache_release(swappage); 1327 page_cache_release(page);
1322 goto repeat; 1328 goto repeat;
1323 } 1329 }
1324 1330
1325 /* We have to do this with page locked to prevent races */ 1331 /* We have to do this with page locked to prevent races */
1326 if (!trylock_page(swappage)) { 1332 if (!trylock_page(page)) {
1327 shmem_swp_unmap(entry); 1333 shmem_swp_unmap(entry);
1328 spin_unlock(&info->lock); 1334 spin_unlock(&info->lock);
1329 wait_on_page_locked(swappage); 1335 wait_on_page_locked(page);
1330 page_cache_release(swappage); 1336 page_cache_release(page);
1331 goto repeat; 1337 goto repeat;
1332 } 1338 }
1333 if (PageWriteback(swappage)) { 1339 if (PageWriteback(page)) {
1334 shmem_swp_unmap(entry); 1340 shmem_swp_unmap(entry);
1335 spin_unlock(&info->lock); 1341 spin_unlock(&info->lock);
1336 wait_on_page_writeback(swappage); 1342 wait_on_page_writeback(page);
1337 unlock_page(swappage); 1343 unlock_page(page);
1338 page_cache_release(swappage); 1344 page_cache_release(page);
1339 goto repeat; 1345 goto repeat;
1340 } 1346 }
1341 if (!PageUptodate(swappage)) { 1347 if (!PageUptodate(page)) {
1342 shmem_swp_unmap(entry); 1348 shmem_swp_unmap(entry);
1343 spin_unlock(&info->lock); 1349 spin_unlock(&info->lock);
1344 unlock_page(swappage); 1350 unlock_page(page);
1345 page_cache_release(swappage); 1351 page_cache_release(page);
1346 error = -EIO; 1352 error = -EIO;
1347 goto failed; 1353 goto out;
1348 } 1354 }
1349 1355
1350 if (filepage) { 1356 error = add_to_page_cache_locked(page, mapping,
1351 shmem_swp_set(info, entry, 0); 1357 idx, GFP_NOWAIT);
1352 shmem_swp_unmap(entry); 1358 if (error) {
1353 delete_from_swap_cache(swappage);
1354 spin_unlock(&info->lock);
1355 copy_highpage(filepage, swappage);
1356 unlock_page(swappage);
1357 page_cache_release(swappage);
1358 flush_dcache_page(filepage);
1359 SetPageUptodate(filepage);
1360 set_page_dirty(filepage);
1361 swap_free(swap);
1362 } else if (!(error = add_to_page_cache_locked(swappage, mapping,
1363 idx, GFP_NOWAIT))) {
1364 info->flags |= SHMEM_PAGEIN;
1365 shmem_swp_set(info, entry, 0);
1366 shmem_swp_unmap(entry);
1367 delete_from_swap_cache(swappage);
1368 spin_unlock(&info->lock);
1369 filepage = swappage;
1370 set_page_dirty(filepage);
1371 swap_free(swap);
1372 } else {
1373 shmem_swp_unmap(entry); 1359 shmem_swp_unmap(entry);
1374 spin_unlock(&info->lock); 1360 spin_unlock(&info->lock);
1375 if (error == -ENOMEM) { 1361 if (error == -ENOMEM) {
@@ -1378,28 +1364,33 @@ repeat:
1378 * call memcg's OOM if needed. 1364 * call memcg's OOM if needed.
1379 */ 1365 */
1380 error = mem_cgroup_shmem_charge_fallback( 1366 error = mem_cgroup_shmem_charge_fallback(
1381 swappage, 1367 page, current->mm, gfp);
1382 current->mm,
1383 gfp);
1384 if (error) { 1368 if (error) {
1385 unlock_page(swappage); 1369 unlock_page(page);
1386 page_cache_release(swappage); 1370 page_cache_release(page);
1387 goto failed; 1371 goto out;
1388 } 1372 }
1389 } 1373 }
1390 unlock_page(swappage); 1374 unlock_page(page);
1391 page_cache_release(swappage); 1375 page_cache_release(page);
1392 goto repeat; 1376 goto repeat;
1393 } 1377 }
1394 } else if (sgp == SGP_READ && !filepage) { 1378
1379 info->flags |= SHMEM_PAGEIN;
1380 shmem_swp_set(info, entry, 0);
1395 shmem_swp_unmap(entry); 1381 shmem_swp_unmap(entry);
1396 filepage = find_get_page(mapping, idx); 1382 delete_from_swap_cache(page);
1397 if (filepage && 1383 spin_unlock(&info->lock);
1398 (!PageUptodate(filepage) || !trylock_page(filepage))) { 1384 set_page_dirty(page);
1385 swap_free(swap);
1386
1387 } else if (sgp == SGP_READ) {
1388 shmem_swp_unmap(entry);
1389 page = find_get_page(mapping, idx);
1390 if (page && !trylock_page(page)) {
1399 spin_unlock(&info->lock); 1391 spin_unlock(&info->lock);
1400 wait_on_page_locked(filepage); 1392 wait_on_page_locked(page);
1401 page_cache_release(filepage); 1393 page_cache_release(page);
1402 filepage = NULL;
1403 goto repeat; 1394 goto repeat;
1404 } 1395 }
1405 spin_unlock(&info->lock); 1396 spin_unlock(&info->lock);
@@ -1417,56 +1408,52 @@ repeat:
1417 } else if (shmem_acct_block(info->flags)) 1408 } else if (shmem_acct_block(info->flags))
1418 goto nospace; 1409 goto nospace;
1419 1410
1420 if (!filepage) { 1411 page = prealloc_page;
1421 int ret; 1412 prealloc_page = NULL;
1422 1413
1423 filepage = prealloc_page; 1414 entry = shmem_swp_alloc(info, idx, sgp, gfp);
1424 prealloc_page = NULL; 1415 if (IS_ERR(entry))
1425 1416 error = PTR_ERR(entry);
1426 entry = shmem_swp_alloc(info, idx, sgp, gfp); 1417 else {
1427 if (IS_ERR(entry)) 1418 swap = *entry;
1428 error = PTR_ERR(entry); 1419 shmem_swp_unmap(entry);
1429 else { 1420 }
1430 swap = *entry; 1421 ret = error || swap.val;
1431 shmem_swp_unmap(entry); 1422 if (ret)
1432 } 1423 mem_cgroup_uncharge_cache_page(page);
1433 ret = error || swap.val; 1424 else
1434 if (ret) 1425 ret = add_to_page_cache_lru(page, mapping,
1435 mem_cgroup_uncharge_cache_page(filepage);
1436 else
1437 ret = add_to_page_cache_lru(filepage, mapping,
1438 idx, GFP_NOWAIT); 1426 idx, GFP_NOWAIT);
1439 /* 1427 /*
1440 * At add_to_page_cache_lru() failure, uncharge will 1428 * At add_to_page_cache_lru() failure,
1441 * be done automatically. 1429 * uncharge will be done automatically.
1442 */ 1430 */
1443 if (ret) { 1431 if (ret) {
1444 shmem_unacct_blocks(info->flags, 1); 1432 shmem_unacct_blocks(info->flags, 1);
1445 shmem_free_blocks(inode, 1); 1433 shmem_free_blocks(inode, 1);
1446 spin_unlock(&info->lock); 1434 spin_unlock(&info->lock);
1447 page_cache_release(filepage); 1435 page_cache_release(page);
1448 filepage = NULL; 1436 if (error)
1449 if (error) 1437 goto out;
1450 goto failed; 1438 goto repeat;
1451 goto repeat;
1452 }
1453 info->flags |= SHMEM_PAGEIN;
1454 } 1439 }
1455 1440
1441 info->flags |= SHMEM_PAGEIN;
1456 info->alloced++; 1442 info->alloced++;
1457 spin_unlock(&info->lock); 1443 spin_unlock(&info->lock);
1458 clear_highpage(filepage); 1444 clear_highpage(page);
1459 flush_dcache_page(filepage); 1445 flush_dcache_page(page);
1460 SetPageUptodate(filepage); 1446 SetPageUptodate(page);
1461 if (sgp == SGP_DIRTY) 1447 if (sgp == SGP_DIRTY)
1462 set_page_dirty(filepage); 1448 set_page_dirty(page);
1449
1463 } else { 1450 } else {
1464 spin_unlock(&info->lock); 1451 spin_unlock(&info->lock);
1465 error = -ENOMEM; 1452 error = -ENOMEM;
1466 goto out; 1453 goto out;
1467 } 1454 }
1468done: 1455done:
1469 *pagep = filepage; 1456 *pagep = page;
1470 error = 0; 1457 error = 0;
1471out: 1458out:
1472 if (prealloc_page) { 1459 if (prealloc_page) {
@@ -1482,21 +1469,13 @@ nospace:
1482 * but must also avoid reporting a spurious ENOSPC while working on a 1469 * but must also avoid reporting a spurious ENOSPC while working on a
1483 * full tmpfs. 1470 * full tmpfs.
1484 */ 1471 */
1485 if (!filepage) { 1472 page = find_get_page(mapping, idx);
1486 struct page *page = find_get_page(mapping, idx);
1487 if (page) {
1488 spin_unlock(&info->lock);
1489 page_cache_release(page);
1490 goto repeat;
1491 }
1492 }
1493 spin_unlock(&info->lock); 1473 spin_unlock(&info->lock);
1494 error = -ENOSPC; 1474 if (page) {
1495failed: 1475 page_cache_release(page);
1496 if (filepage) { 1476 goto repeat;
1497 unlock_page(filepage);
1498 page_cache_release(filepage);
1499 } 1477 }
1478 error = -ENOSPC;
1500 goto out; 1479 goto out;
1501} 1480}
1502 1481