diff options
author | Jaegeuk Kim <jaegeuk@kernel.org> | 2015-04-09 14:20:42 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2015-05-28 18:41:30 -0400 |
commit | f1e8866016b53bd0ea108ae9adbb52da1dd53dab (patch) | |
tree | a88d57784acff179c93b4119c0b55d0656860d6b /fs/f2fs/data.c | |
parent | 26d815ad75156a1cf2f6c7ba94cdfd32849879d7 (diff) |
f2fs: expose f2fs_mpage_readpages
This patch implements f2fs_mpage_readpages for further optimization on
encryption support.
The basic code was taken from fs/mpage.c, and changed to be simple by adjusting
that block_size is equal to page_size in f2fs.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs/data.c')
-rw-r--r-- | fs/f2fs/data.c | 157 |
1 files changed, 154 insertions, 3 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index aa3c079ffd94..2a3a9cd008da 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/bio.h> | 18 | #include <linux/bio.h> |
19 | #include <linux/prefetch.h> | 19 | #include <linux/prefetch.h> |
20 | #include <linux/uio.h> | 20 | #include <linux/uio.h> |
21 | #include <linux/cleancache.h> | ||
21 | 22 | ||
22 | #include "f2fs.h" | 23 | #include "f2fs.h" |
23 | #include "node.h" | 24 | #include "node.h" |
@@ -47,6 +48,30 @@ static void f2fs_read_end_io(struct bio *bio, int err) | |||
47 | bio_put(bio); | 48 | bio_put(bio); |
48 | } | 49 | } |
49 | 50 | ||
51 | /* | ||
52 | * I/O completion handler for multipage BIOs. | ||
53 | * copied from fs/mpage.c | ||
54 | */ | ||
55 | static void mpage_end_io(struct bio *bio, int err) | ||
56 | { | ||
57 | struct bio_vec *bv; | ||
58 | int i; | ||
59 | |||
60 | bio_for_each_segment_all(bv, bio, i) { | ||
61 | struct page *page = bv->bv_page; | ||
62 | |||
63 | if (!err) { | ||
64 | SetPageUptodate(page); | ||
65 | } else { | ||
66 | ClearPageUptodate(page); | ||
67 | SetPageError(page); | ||
68 | } | ||
69 | unlock_page(page); | ||
70 | } | ||
71 | |||
72 | bio_put(bio); | ||
73 | } | ||
74 | |||
50 | static void f2fs_write_end_io(struct bio *bio, int err) | 75 | static void f2fs_write_end_io(struct bio *bio, int err) |
51 | { | 76 | { |
52 | struct f2fs_sb_info *sbi = bio->bi_private; | 77 | struct f2fs_sb_info *sbi = bio->bi_private; |
@@ -1349,6 +1374,133 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
1349 | start, len, get_data_block_fiemap); | 1374 | start, len, get_data_block_fiemap); |
1350 | } | 1375 | } |
1351 | 1376 | ||
1377 | /* | ||
1378 | * This function was originally taken from fs/mpage.c, and customized for f2fs. | ||
1379 | * Major change was from block_size == page_size in f2fs by default. | ||
1380 | */ | ||
1381 | static int f2fs_mpage_readpages(struct address_space *mapping, | ||
1382 | struct list_head *pages, struct page *page, | ||
1383 | unsigned nr_pages) | ||
1384 | { | ||
1385 | struct bio *bio = NULL; | ||
1386 | unsigned page_idx; | ||
1387 | sector_t last_block_in_bio = 0; | ||
1388 | struct inode *inode = mapping->host; | ||
1389 | const unsigned blkbits = inode->i_blkbits; | ||
1390 | const unsigned blocksize = 1 << blkbits; | ||
1391 | sector_t block_in_file; | ||
1392 | sector_t last_block; | ||
1393 | sector_t last_block_in_file; | ||
1394 | sector_t block_nr; | ||
1395 | struct block_device *bdev = inode->i_sb->s_bdev; | ||
1396 | struct f2fs_map_blocks map; | ||
1397 | |||
1398 | map.m_pblk = 0; | ||
1399 | map.m_lblk = 0; | ||
1400 | map.m_len = 0; | ||
1401 | map.m_flags = 0; | ||
1402 | |||
1403 | for (page_idx = 0; nr_pages; page_idx++, nr_pages--) { | ||
1404 | |||
1405 | prefetchw(&page->flags); | ||
1406 | if (pages) { | ||
1407 | page = list_entry(pages->prev, struct page, lru); | ||
1408 | list_del(&page->lru); | ||
1409 | if (add_to_page_cache_lru(page, mapping, | ||
1410 | page->index, GFP_KERNEL)) | ||
1411 | goto next_page; | ||
1412 | } | ||
1413 | |||
1414 | block_in_file = (sector_t)page->index; | ||
1415 | last_block = block_in_file + nr_pages; | ||
1416 | last_block_in_file = (i_size_read(inode) + blocksize - 1) >> | ||
1417 | blkbits; | ||
1418 | if (last_block > last_block_in_file) | ||
1419 | last_block = last_block_in_file; | ||
1420 | |||
1421 | /* | ||
1422 | * Map blocks using the previous result first. | ||
1423 | */ | ||
1424 | if ((map.m_flags & F2FS_MAP_MAPPED) && | ||
1425 | block_in_file > map.m_lblk && | ||
1426 | block_in_file < (map.m_lblk + map.m_len)) | ||
1427 | goto got_it; | ||
1428 | |||
1429 | /* | ||
1430 | * Then do more f2fs_map_blocks() calls until we are | ||
1431 | * done with this page. | ||
1432 | */ | ||
1433 | map.m_flags = 0; | ||
1434 | |||
1435 | if (block_in_file < last_block) { | ||
1436 | map.m_lblk = block_in_file; | ||
1437 | map.m_len = last_block - block_in_file; | ||
1438 | |||
1439 | if (f2fs_map_blocks(inode, &map, 0, false)) | ||
1440 | goto set_error_page; | ||
1441 | } | ||
1442 | got_it: | ||
1443 | if ((map.m_flags & F2FS_MAP_MAPPED)) { | ||
1444 | block_nr = map.m_pblk + block_in_file - map.m_lblk; | ||
1445 | SetPageMappedToDisk(page); | ||
1446 | |||
1447 | if (!PageUptodate(page) && !cleancache_get_page(page)) { | ||
1448 | SetPageUptodate(page); | ||
1449 | goto confused; | ||
1450 | } | ||
1451 | } else { | ||
1452 | zero_user_segment(page, 0, PAGE_CACHE_SIZE); | ||
1453 | SetPageUptodate(page); | ||
1454 | unlock_page(page); | ||
1455 | goto next_page; | ||
1456 | } | ||
1457 | |||
1458 | /* | ||
1459 | * This page will go to BIO. Do we need to send this | ||
1460 | * BIO off first? | ||
1461 | */ | ||
1462 | if (bio && (last_block_in_bio != block_nr - 1)) { | ||
1463 | submit_and_realloc: | ||
1464 | submit_bio(READ, bio); | ||
1465 | bio = NULL; | ||
1466 | } | ||
1467 | if (bio == NULL) { | ||
1468 | bio = bio_alloc(GFP_KERNEL, | ||
1469 | min_t(int, nr_pages, bio_get_nr_vecs(bdev))); | ||
1470 | if (!bio) | ||
1471 | goto set_error_page; | ||
1472 | bio->bi_bdev = bdev; | ||
1473 | bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(block_nr); | ||
1474 | bio->bi_end_io = mpage_end_io; | ||
1475 | bio->bi_private = NULL; | ||
1476 | } | ||
1477 | |||
1478 | if (bio_add_page(bio, page, blocksize, 0) < blocksize) | ||
1479 | goto submit_and_realloc; | ||
1480 | |||
1481 | last_block_in_bio = block_nr; | ||
1482 | goto next_page; | ||
1483 | set_error_page: | ||
1484 | SetPageError(page); | ||
1485 | zero_user_segment(page, 0, PAGE_CACHE_SIZE); | ||
1486 | unlock_page(page); | ||
1487 | goto next_page; | ||
1488 | confused: | ||
1489 | if (bio) { | ||
1490 | submit_bio(READ, bio); | ||
1491 | bio = NULL; | ||
1492 | } | ||
1493 | unlock_page(page); | ||
1494 | next_page: | ||
1495 | if (pages) | ||
1496 | page_cache_release(page); | ||
1497 | } | ||
1498 | BUG_ON(pages && !list_empty(pages)); | ||
1499 | if (bio) | ||
1500 | submit_bio(READ, bio); | ||
1501 | return 0; | ||
1502 | } | ||
1503 | |||
1352 | static int f2fs_read_data_page(struct file *file, struct page *page) | 1504 | static int f2fs_read_data_page(struct file *file, struct page *page) |
1353 | { | 1505 | { |
1354 | struct inode *inode = page->mapping->host; | 1506 | struct inode *inode = page->mapping->host; |
@@ -1360,8 +1512,7 @@ static int f2fs_read_data_page(struct file *file, struct page *page) | |||
1360 | if (f2fs_has_inline_data(inode)) | 1512 | if (f2fs_has_inline_data(inode)) |
1361 | ret = f2fs_read_inline_data(inode, page); | 1513 | ret = f2fs_read_inline_data(inode, page); |
1362 | if (ret == -EAGAIN) | 1514 | if (ret == -EAGAIN) |
1363 | ret = mpage_readpage(page, get_data_block); | 1515 | ret = f2fs_mpage_readpages(page->mapping, NULL, page, 1); |
1364 | |||
1365 | return ret; | 1516 | return ret; |
1366 | } | 1517 | } |
1367 | 1518 | ||
@@ -1375,7 +1526,7 @@ static int f2fs_read_data_pages(struct file *file, | |||
1375 | if (f2fs_has_inline_data(inode)) | 1526 | if (f2fs_has_inline_data(inode)) |
1376 | return 0; | 1527 | return 0; |
1377 | 1528 | ||
1378 | return mpage_readpages(mapping, pages, nr_pages, get_data_block); | 1529 | return f2fs_mpage_readpages(mapping, pages, NULL, nr_pages); |
1379 | } | 1530 | } |
1380 | 1531 | ||
1381 | int do_write_data_page(struct page *page, struct f2fs_io_info *fio) | 1532 | int do_write_data_page(struct page *page, struct f2fs_io_info *fio) |