aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/ext4.h2
-rw-r--r--fs/ext4/extents.c9
-rw-r--r--fs/ext4/extents_status.c60
-rw-r--r--fs/ext4/extents_status.h2
-rw-r--r--fs/ext4/inode.c66
-rw-r--r--include/trace/events/ext4.h56
6 files changed, 192 insertions, 3 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 5c31d6ac9500..329e7fba47d6 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -579,6 +579,8 @@ enum {
579#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080 579#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
580 /* Do not take i_data_sem locking in ext4_map_blocks */ 580 /* Do not take i_data_sem locking in ext4_map_blocks */
581#define EXT4_GET_BLOCKS_NO_LOCK 0x0100 581#define EXT4_GET_BLOCKS_NO_LOCK 0x0100
582 /* Do not put hole in extent cache */
583#define EXT4_GET_BLOCKS_NO_PUT_HOLE 0x0200
582 584
583/* 585/*
584 * Flags used by ext4_free_blocks 586 * Flags used by ext4_free_blocks
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index be0b1b3eed97..b9d7a2363736 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -2167,6 +2167,9 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
2167 block, 2167 block,
2168 le32_to_cpu(ex->ee_block), 2168 le32_to_cpu(ex->ee_block),
2169 ext4_ext_get_actual_len(ex)); 2169 ext4_ext_get_actual_len(ex));
2170 if (!ext4_find_delalloc_range(inode, lblock, lblock + len - 1))
2171 ext4_es_insert_extent(inode, lblock, len, ~0,
2172 EXTENT_STATUS_HOLE);
2170 } else if (block >= le32_to_cpu(ex->ee_block) 2173 } else if (block >= le32_to_cpu(ex->ee_block)
2171 + ext4_ext_get_actual_len(ex)) { 2174 + ext4_ext_get_actual_len(ex)) {
2172 ext4_lblk_t next; 2175 ext4_lblk_t next;
@@ -2180,6 +2183,9 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
2180 block); 2183 block);
2181 BUG_ON(next == lblock); 2184 BUG_ON(next == lblock);
2182 len = next - lblock; 2185 len = next - lblock;
2186 if (!ext4_find_delalloc_range(inode, lblock, lblock + len - 1))
2187 ext4_es_insert_extent(inode, lblock, len, ~0,
2188 EXTENT_STATUS_HOLE);
2183 } else { 2189 } else {
2184 lblock = len = 0; 2190 lblock = len = 0;
2185 BUG(); 2191 BUG();
@@ -4018,7 +4024,8 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
4018 * put just found gap into cache to speed up 4024 * put just found gap into cache to speed up
4019 * subsequent requests 4025 * subsequent requests
4020 */ 4026 */
4021 ext4_ext_put_gap_in_cache(inode, path, map->m_lblk); 4027 if ((flags & EXT4_GET_BLOCKS_NO_PUT_HOLE) == 0)
4028 ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
4022 goto out2; 4029 goto out2;
4023 } 4030 }
4024 4031
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
index 76f4351ea821..eeb893122d8d 100644
--- a/fs/ext4/extents_status.c
+++ b/fs/ext4/extents_status.c
@@ -461,6 +461,66 @@ error:
461 return err; 461 return err;
462} 462}
463 463
464/*
465 * ext4_es_lookup_extent() looks up an extent in extent status tree.
466 *
467 * ext4_es_lookup_extent is called by ext4_map_blocks/ext4_da_map_blocks.
468 *
469 * Return: 1 on found, 0 on not
470 */
471int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
472 struct extent_status *es)
473{
474 struct ext4_es_tree *tree;
475 struct extent_status *es1 = NULL;
476 struct rb_node *node;
477 int found = 0;
478
479 trace_ext4_es_lookup_extent_enter(inode, lblk);
480 es_debug("lookup extent in block %u\n", lblk);
481
482 tree = &EXT4_I(inode)->i_es_tree;
483 read_lock(&EXT4_I(inode)->i_es_lock);
484
485 /* find extent in cache firstly */
486 es->es_lblk = es->es_len = es->es_pblk = 0;
487 if (tree->cache_es) {
488 es1 = tree->cache_es;
489 if (in_range(lblk, es1->es_lblk, es1->es_len)) {
490 es_debug("%u cached by [%u/%u)\n",
491 lblk, es1->es_lblk, es1->es_len);
492 found = 1;
493 goto out;
494 }
495 }
496
497 node = tree->root.rb_node;
498 while (node) {
499 es1 = rb_entry(node, struct extent_status, rb_node);
500 if (lblk < es1->es_lblk)
501 node = node->rb_left;
502 else if (lblk > ext4_es_end(es1))
503 node = node->rb_right;
504 else {
505 found = 1;
506 break;
507 }
508 }
509
510out:
511 if (found) {
512 BUG_ON(!es1);
513 es->es_lblk = es1->es_lblk;
514 es->es_len = es1->es_len;
515 es->es_pblk = es1->es_pblk;
516 }
517
518 read_unlock(&EXT4_I(inode)->i_es_lock);
519
520 trace_ext4_es_lookup_extent_exit(inode, es, found);
521 return found;
522}
523
464static int __es_remove_extent(struct ext4_es_tree *tree, ext4_lblk_t lblk, 524static int __es_remove_extent(struct ext4_es_tree *tree, ext4_lblk_t lblk,
465 ext4_lblk_t end) 525 ext4_lblk_t end)
466{ 526{
diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h
index 3f69d097c6e7..8ffc90c784fa 100644
--- a/fs/ext4/extents_status.h
+++ b/fs/ext4/extents_status.h
@@ -53,6 +53,8 @@ extern int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
53 ext4_lblk_t len); 53 ext4_lblk_t len);
54extern void ext4_es_find_delayed_extent(struct inode *inode, ext4_lblk_t lblk, 54extern void ext4_es_find_delayed_extent(struct inode *inode, ext4_lblk_t lblk,
55 struct extent_status *es); 55 struct extent_status *es);
56extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
57 struct extent_status *es);
56 58
57static inline int ext4_es_is_written(struct extent_status *es) 59static inline int ext4_es_is_written(struct extent_status *es)
58{ 60{
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 576b586b61aa..95a0c62c5683 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -507,12 +507,33 @@ static pgoff_t ext4_num_dirty_pages(struct inode *inode, pgoff_t idx,
507int ext4_map_blocks(handle_t *handle, struct inode *inode, 507int ext4_map_blocks(handle_t *handle, struct inode *inode,
508 struct ext4_map_blocks *map, int flags) 508 struct ext4_map_blocks *map, int flags)
509{ 509{
510 struct extent_status es;
510 int retval; 511 int retval;
511 512
512 map->m_flags = 0; 513 map->m_flags = 0;
513 ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u," 514 ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u,"
514 "logical block %lu\n", inode->i_ino, flags, map->m_len, 515 "logical block %lu\n", inode->i_ino, flags, map->m_len,
515 (unsigned long) map->m_lblk); 516 (unsigned long) map->m_lblk);
517
518 /* Lookup extent status tree firstly */
519 if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) {
520 if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) {
521 map->m_pblk = ext4_es_pblock(&es) +
522 map->m_lblk - es.es_lblk;
523 map->m_flags |= ext4_es_is_written(&es) ?
524 EXT4_MAP_MAPPED : EXT4_MAP_UNWRITTEN;
525 retval = es.es_len - (map->m_lblk - es.es_lblk);
526 if (retval > map->m_len)
527 retval = map->m_len;
528 map->m_len = retval;
529 } else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) {
530 retval = 0;
531 } else {
532 BUG_ON(1);
533 }
534 goto found;
535 }
536
516 /* 537 /*
517 * Try to see if we can get the block without requesting a new 538 * Try to see if we can get the block without requesting a new
518 * file system block. 539 * file system block.
@@ -544,6 +565,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode,
544 if (!(flags & EXT4_GET_BLOCKS_NO_LOCK)) 565 if (!(flags & EXT4_GET_BLOCKS_NO_LOCK))
545 up_read((&EXT4_I(inode)->i_data_sem)); 566 up_read((&EXT4_I(inode)->i_data_sem));
546 567
568found:
547 if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { 569 if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
548 int ret = check_block_validity(inode, map); 570 int ret = check_block_validity(inode, map);
549 if (ret != 0) 571 if (ret != 0)
@@ -1743,6 +1765,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
1743 struct ext4_map_blocks *map, 1765 struct ext4_map_blocks *map,
1744 struct buffer_head *bh) 1766 struct buffer_head *bh)
1745{ 1767{
1768 struct extent_status es;
1746 int retval; 1769 int retval;
1747 sector_t invalid_block = ~((sector_t) 0xffff); 1770 sector_t invalid_block = ~((sector_t) 0xffff);
1748 1771
@@ -1753,6 +1776,42 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
1753 ext_debug("ext4_da_map_blocks(): inode %lu, max_blocks %u," 1776 ext_debug("ext4_da_map_blocks(): inode %lu, max_blocks %u,"
1754 "logical block %lu\n", inode->i_ino, map->m_len, 1777 "logical block %lu\n", inode->i_ino, map->m_len,
1755 (unsigned long) map->m_lblk); 1778 (unsigned long) map->m_lblk);
1779
1780 /* Lookup extent status tree firstly */
1781 if (ext4_es_lookup_extent(inode, iblock, &es)) {
1782
1783 if (ext4_es_is_hole(&es)) {
1784 retval = 0;
1785 down_read((&EXT4_I(inode)->i_data_sem));
1786 goto add_delayed;
1787 }
1788
1789 /*
1790 * Delayed extent could be allocated by fallocate.
1791 * So we need to check it.
1792 */
1793 if (ext4_es_is_delayed(&es) && !ext4_es_is_unwritten(&es)) {
1794 map_bh(bh, inode->i_sb, invalid_block);
1795 set_buffer_new(bh);
1796 set_buffer_delay(bh);
1797 return 0;
1798 }
1799
1800 map->m_pblk = ext4_es_pblock(&es) + iblock - es.es_lblk;
1801 retval = es.es_len - (iblock - es.es_lblk);
1802 if (retval > map->m_len)
1803 retval = map->m_len;
1804 map->m_len = retval;
1805 if (ext4_es_is_written(&es))
1806 map->m_flags |= EXT4_MAP_MAPPED;
1807 else if (ext4_es_is_unwritten(&es))
1808 map->m_flags |= EXT4_MAP_UNWRITTEN;
1809 else
1810 BUG_ON(1);
1811
1812 return retval;
1813 }
1814
1756 /* 1815 /*
1757 * Try to see if we can get the block without requesting a new 1816 * Try to see if we can get the block without requesting a new
1758 * file system block. 1817 * file system block.
@@ -1771,10 +1830,13 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock,
1771 map->m_flags |= EXT4_MAP_FROM_CLUSTER; 1830 map->m_flags |= EXT4_MAP_FROM_CLUSTER;
1772 retval = 0; 1831 retval = 0;
1773 } else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) 1832 } else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
1774 retval = ext4_ext_map_blocks(NULL, inode, map, 0); 1833 retval = ext4_ext_map_blocks(NULL, inode, map,
1834 EXT4_GET_BLOCKS_NO_PUT_HOLE);
1775 else 1835 else
1776 retval = ext4_ind_map_blocks(NULL, inode, map, 0); 1836 retval = ext4_ind_map_blocks(NULL, inode, map,
1837 EXT4_GET_BLOCKS_NO_PUT_HOLE);
1777 1838
1839add_delayed:
1778 if (retval == 0) { 1840 if (retval == 0) {
1779 int ret; 1841 int ret;
1780 /* 1842 /*
diff --git a/include/trace/events/ext4.h b/include/trace/events/ext4.h
index c121cdf55ab3..1e590b68cec4 100644
--- a/include/trace/events/ext4.h
+++ b/include/trace/events/ext4.h
@@ -2199,6 +2199,62 @@ TRACE_EVENT(ext4_es_find_delayed_extent_exit,
2199 __entry->pblk, __entry->status) 2199 __entry->pblk, __entry->status)
2200); 2200);
2201 2201
2202TRACE_EVENT(ext4_es_lookup_extent_enter,
2203 TP_PROTO(struct inode *inode, ext4_lblk_t lblk),
2204
2205 TP_ARGS(inode, lblk),
2206
2207 TP_STRUCT__entry(
2208 __field( dev_t, dev )
2209 __field( ino_t, ino )
2210 __field( ext4_lblk_t, lblk )
2211 ),
2212
2213 TP_fast_assign(
2214 __entry->dev = inode->i_sb->s_dev;
2215 __entry->ino = inode->i_ino;
2216 __entry->lblk = lblk;
2217 ),
2218
2219 TP_printk("dev %d,%d ino %lu lblk %u",
2220 MAJOR(__entry->dev), MINOR(__entry->dev),
2221 (unsigned long) __entry->ino, __entry->lblk)
2222);
2223
2224TRACE_EVENT(ext4_es_lookup_extent_exit,
2225 TP_PROTO(struct inode *inode, struct extent_status *es,
2226 int found),
2227
2228 TP_ARGS(inode, es, found),
2229
2230 TP_STRUCT__entry(
2231 __field( dev_t, dev )
2232 __field( ino_t, ino )
2233 __field( ext4_lblk_t, lblk )
2234 __field( ext4_lblk_t, len )
2235 __field( ext4_fsblk_t, pblk )
2236 __field( unsigned long long, status )
2237 __field( int, found )
2238 ),
2239
2240 TP_fast_assign(
2241 __entry->dev = inode->i_sb->s_dev;
2242 __entry->ino = inode->i_ino;
2243 __entry->lblk = es->es_lblk;
2244 __entry->len = es->es_len;
2245 __entry->pblk = ext4_es_pblock(es);
2246 __entry->status = ext4_es_status(es);
2247 __entry->found = found;
2248 ),
2249
2250 TP_printk("dev %d,%d ino %lu found %d [%u/%u) %llu %llx",
2251 MAJOR(__entry->dev), MINOR(__entry->dev),
2252 (unsigned long) __entry->ino, __entry->found,
2253 __entry->lblk, __entry->len,
2254 __entry->found ? __entry->pblk : 0,
2255 __entry->found ? __entry->status : 0)
2256);
2257
2202#endif /* _TRACE_EXT4_H */ 2258#endif /* _TRACE_EXT4_H */
2203 2259
2204/* This part must be outside protection */ 2260/* This part must be outside protection */