]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/ext4/extents.c
ext4: fix race between writepages and enabling EXT4_EXTENTS_FL
[linux.git] / fs / ext4 / extents.c
index 6e4d8a5cb7fb761a80504ef6df20d8cf788175ec..954013d6076b629330773edcc894edf1a2f6dbfe 100644 (file)
@@ -468,6 +468,30 @@ int ext4_ext_check_inode(struct inode *inode)
        return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode), 0);
 }
 
+static void ext4_cache_extents(struct inode *inode,
+                              struct ext4_extent_header *eh)
+{
+       struct ext4_extent *ex = EXT_FIRST_EXTENT(eh);
+       ext4_lblk_t prev = 0;
+       int i;
+
+       for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) {
+               unsigned int status = EXTENT_STATUS_WRITTEN;
+               ext4_lblk_t lblk = le32_to_cpu(ex->ee_block);
+               int len = ext4_ext_get_actual_len(ex);
+
+               if (prev && (prev != lblk))
+                       ext4_es_cache_extent(inode, prev, lblk - prev, ~0,
+                                            EXTENT_STATUS_HOLE);
+
+               if (ext4_ext_is_unwritten(ex))
+                       status = EXTENT_STATUS_UNWRITTEN;
+               ext4_es_cache_extent(inode, lblk, len,
+                                    ext4_ext_pblock(ex), status);
+               prev = lblk + len;
+       }
+}
+
 static struct buffer_head *
 __read_extent_tree_block(const char *function, unsigned int line,
                         struct inode *inode, ext4_fsblk_t pblk, int depth,
@@ -502,26 +526,7 @@ __read_extent_tree_block(const char *function, unsigned int line,
         */
        if (!(flags & EXT4_EX_NOCACHE) && depth == 0) {
                struct ext4_extent_header *eh = ext_block_hdr(bh);
-               struct ext4_extent *ex = EXT_FIRST_EXTENT(eh);
-               ext4_lblk_t prev = 0;
-               int i;
-
-               for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) {
-                       unsigned int status = EXTENT_STATUS_WRITTEN;
-                       ext4_lblk_t lblk = le32_to_cpu(ex->ee_block);
-                       int len = ext4_ext_get_actual_len(ex);
-
-                       if (prev && (prev != lblk))
-                               ext4_es_cache_extent(inode, prev,
-                                                    lblk - prev, ~0,
-                                                    EXTENT_STATUS_HOLE);
-
-                       if (ext4_ext_is_unwritten(ex))
-                               status = EXTENT_STATUS_UNWRITTEN;
-                       ext4_es_cache_extent(inode, lblk, len,
-                                            ext4_ext_pblock(ex), status);
-                       prev = lblk + len;
-               }
+               ext4_cache_extents(inode, eh);
        }
        return bh;
 errout:
@@ -607,8 +612,9 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
        ext_debug("path:");
        for (k = 0; k <= l; k++, path++) {
                if (path->p_idx) {
-                 ext_debug("  %d->%llu", le32_to_cpu(path->p_idx->ei_block),
-                           ext4_idx_pblock(path->p_idx));
+                       ext_debug("  %d->%llu",
+                                 le32_to_cpu(path->p_idx->ei_block),
+                                 ext4_idx_pblock(path->p_idx));
                } else if (path->p_ext) {
                        ext_debug("  %d:[%d]%d:%llu ",
                                  le32_to_cpu(path->p_ext->ee_block),
@@ -689,11 +695,12 @@ void ext4_ext_drop_refs(struct ext4_ext_path *path)
        if (!path)
                return;
        depth = path->p_depth;
-       for (i = 0; i <= depth; i++, path++)
+       for (i = 0; i <= depth; i++, path++) {
                if (path->p_bh) {
                        brelse(path->p_bh);
                        path->p_bh = NULL;
                }
+       }
 }
 
 /*
@@ -735,8 +742,8 @@ ext4_ext_binsearch_idx(struct inode *inode,
 
                chix = ix = EXT_FIRST_INDEX(eh);
                for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) {
-                 if (k != 0 &&
-                     le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) {
+                       if (k != 0 && le32_to_cpu(ix->ei_block) <=
+                           le32_to_cpu(ix[-1].ei_block)) {
                                printk(KERN_DEBUG "k=%d, ix=0x%p, "
                                       "first=0x%p\n", k,
                                       ix, EXT_FIRST_INDEX(eh));
@@ -869,6 +876,8 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block,
        path[0].p_bh = NULL;
 
        i = depth;
+       if (!(flags & EXT4_EX_NOCACHE) && depth == 0)
+               ext4_cache_extents(inode, eh);
        /* walk through the tree */
        while (i) {
                ext_debug("depth %d: num %d, max %d\n",
@@ -1590,17 +1599,16 @@ ext4_ext_next_allocated_block(struct ext4_ext_path *path)
                return EXT_MAX_BLOCKS;
 
        while (depth >= 0) {
+               struct ext4_ext_path *p = &path[depth];
+
                if (depth == path->p_depth) {
                        /* leaf */
-                       if (path[depth].p_ext &&
-                               path[depth].p_ext !=
-                                       EXT_LAST_EXTENT(path[depth].p_hdr))
-                         return le32_to_cpu(path[depth].p_ext[1].ee_block);
+                       if (p->p_ext && p->p_ext != EXT_LAST_EXTENT(p->p_hdr))
+                               return le32_to_cpu(p->p_ext[1].ee_block);
                } else {
                        /* index */
-                       if (path[depth].p_idx !=
-                                       EXT_LAST_INDEX(path[depth].p_hdr))
-                         return le32_to_cpu(path[depth].p_idx[1].ei_block);
+                       if (p->p_idx != EXT_LAST_INDEX(p->p_hdr))
+                               return le32_to_cpu(p->p_idx[1].ei_block);
                }
                depth--;
        }
@@ -1716,11 +1724,6 @@ static int ext4_can_extents_be_merged(struct inode *inode,
                        le32_to_cpu(ex2->ee_block))
                return 0;
 
-       /*
-        * To allow future support for preallocated extents to be added
-        * as an RO_COMPAT feature, refuse to merge to extents if
-        * this can result in the top bit of ee_len being set.
-        */
        if (ext1_ee_len + ext2_ee_len > EXT_INIT_MAX_LEN)
                return 0;