summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/extents.c15
-rw-r--r--fs/ext4/extents_status.c40
-rw-r--r--fs/ext4/extents_status.h4
-rw-r--r--fs/ext4/file.c6
4 files changed, 34 insertions, 31 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 37f94a751ad7..895c19595ecf 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -3528,8 +3528,7 @@ static int ext4_find_delalloc_range(struct inode *inode,
{
struct extent_status es;
- es.es_lblk = lblk_start;
- (void)ext4_es_find_extent(inode, &es);
+ ext4_es_find_delayed_extent(inode, lblk_start, &es);
if (es.es_len == 0)
return 0; /* there is no delay extent in this tree */
else if (es.es_lblk <= lblk_start &&
@@ -4568,10 +4567,9 @@ static int ext4_find_delayed_extent(struct inode *inode,
struct ext4_ext_cache *newex)
{
struct extent_status es;
- ext4_lblk_t next_del;
+ ext4_lblk_t block, next_del;
- es.es_lblk = newex->ec_block;
- next_del = ext4_es_find_extent(inode, &es);
+ ext4_es_find_delayed_extent(inode, newex->ec_block, &es);
if (newex->ec_start == 0) {
/*
@@ -4592,6 +4590,13 @@ static int ext4_find_delayed_extent(struct inode *inode,
newex->ec_len = es.es_lblk + es.es_len - newex->ec_block;
}
+ block = newex->ec_block + newex->ec_len;
+ ext4_es_find_delayed_extent(inode, block, &es);
+ if (es.es_len == 0)
+ next_del = EXT_MAX_BLOCKS;
+ else
+ next_del = es.es_lblk;
+
return next_del;
}
/* fiemap flags we can handle specified here */
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
index 1f5fd44993e9..76f4351ea821 100644
--- a/fs/ext4/extents_status.c
+++ b/fs/ext4/extents_status.c
@@ -229,59 +229,59 @@ static struct extent_status *__es_tree_search(struct rb_root *root,
}
/*
- * ext4_es_find_extent: find the 1st delayed extent covering @es->lblk
+ * ext4_es_find_delayed_extent: find the 1st delayed extent covering @es->lblk
* if it exists, otherwise, the next extent after @es->lblk.
*
* @inode: the inode which owns delayed extents
+ * @lblk: the offset where we start to search
* @es: delayed extent that we found
- *
- * Returns the first block of the next extent after es, otherwise
- * EXT_MAX_BLOCKS if no extent is found.
- * Delayed extent is returned via @es.
*/
-ext4_lblk_t ext4_es_find_extent(struct inode *inode, struct extent_status *es)
+void ext4_es_find_delayed_extent(struct inode *inode, ext4_lblk_t lblk,
+ struct extent_status *es)
{
struct ext4_es_tree *tree = NULL;
struct extent_status *es1 = NULL;
struct rb_node *node;
- ext4_lblk_t ret = EXT_MAX_BLOCKS;
- trace_ext4_es_find_extent_enter(inode, es->es_lblk);
+ BUG_ON(es == NULL);
+ trace_ext4_es_find_delayed_extent_enter(inode, lblk);
read_lock(&EXT4_I(inode)->i_es_lock);
tree = &EXT4_I(inode)->i_es_tree;
/* find extent in cache firstly */
- es->es_len = es->es_pblk = 0;
+ es->es_lblk = es->es_len = es->es_pblk = 0;
if (tree->cache_es) {
es1 = tree->cache_es;
- if (in_range(es->es_lblk, es1->es_lblk, es1->es_len)) {
+ if (in_range(lblk, es1->es_lblk, es1->es_len)) {
es_debug("%u cached by [%u/%u) %llu %llx\n",
- es->es_lblk, es1->es_lblk, es1->es_len,
+ lblk, es1->es_lblk, es1->es_len,
ext4_es_pblock(es1), ext4_es_status(es1));
goto out;
}
}
- es1 = __es_tree_search(&tree->root, es->es_lblk);
+ es1 = __es_tree_search(&tree->root, lblk);
out:
- if (es1) {
+ if (es1 && !ext4_es_is_delayed(es1)) {
+ while ((node = rb_next(&es1->rb_node)) != NULL) {
+ es1 = rb_entry(node, struct extent_status, rb_node);
+ if (ext4_es_is_delayed(es1))
+ break;
+ }
+ }
+
+ if (es1 && ext4_es_is_delayed(es1)) {
tree->cache_es = es1;
es->es_lblk = es1->es_lblk;
es->es_len = es1->es_len;
es->es_pblk = es1->es_pblk;
- node = rb_next(&es1->rb_node);
- if (node) {
- es1 = rb_entry(node, struct extent_status, rb_node);
- ret = es1->es_lblk;
- }
}
read_unlock(&EXT4_I(inode)->i_es_lock);
- trace_ext4_es_find_extent_exit(inode, es, ret);
- return ret;
+ trace_ext4_es_find_delayed_extent_exit(inode, es);
}
static struct extent_status *
diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h
index 3cad83303adb..3f69d097c6e7 100644
--- a/fs/ext4/extents_status.h
+++ b/fs/ext4/extents_status.h
@@ -51,8 +51,8 @@ extern int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
unsigned long long status);
extern int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
ext4_lblk_t len);
-extern ext4_lblk_t ext4_es_find_extent(struct inode *inode,
- struct extent_status *es);
+extern void ext4_es_find_delayed_extent(struct inode *inode, ext4_lblk_t lblk,
+ struct extent_status *es);
static inline int ext4_es_is_written(struct extent_status *es)
{
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 2df9354b105e..7e85a10a6f4f 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -464,8 +464,7 @@ static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize)
* If there is a delay extent at this offset,
* it will be as a data.
*/
- es.es_lblk = last;
- (void)ext4_es_find_extent(inode, &es);
+ ext4_es_find_delayed_extent(inode, last, &es);
if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) {
if (last != start)
dataoff = last << blkbits;
@@ -548,8 +547,7 @@ static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize)
* If there is a delay extent at this offset,
* we will skip this extent.
*/
- es.es_lblk = last;
- (void)ext4_es_find_extent(inode, &es);
+ ext4_es_find_delayed_extent(inode, last, &es);
if (es.es_len != 0 && in_range(last, es.es_lblk, es.es_len)) {
last = es.es_lblk + es.es_len;
holeoff = last << blkbits;
OpenPOWER on IntegriCloud