Whamcloud - gitweb
Merge branch 'maint' into next
[tools/e2fsprogs.git] / lib / ext2fs / extent.c
index c12bc93..c0b34a7 100644 (file)
@@ -60,6 +60,7 @@ struct ext2_extent_handle {
        int                     type;
        int                     level;
        int                     max_depth;
+       int                     max_paths;
        struct extent_path      *path;
 };
 
@@ -198,7 +199,7 @@ void ext2fs_extent_free(ext2_extent_handle_t handle)
                return;
 
        if (handle->path) {
-               for (i=1; i <= handle->max_depth; i++) {
+               for (i = 1; i < handle->max_paths; i++) {
                        if (handle->path[i].buf)
                                ext2fs_free_mem(&handle->path[i].buf);
                }
@@ -272,11 +273,10 @@ errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino,
        handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth);
        handle->type = ext2fs_le16_to_cpu(eh->eh_magic);
 
-       retval = ext2fs_get_mem(((handle->max_depth+1) *
-                                sizeof(struct extent_path)),
-                               &handle->path);
-       memset(handle->path, 0,
-              (handle->max_depth+1) * sizeof(struct extent_path));
+       handle->max_paths = handle->max_depth + 1;
+       retval = ext2fs_get_memzero(handle->max_paths *
+                                   sizeof(struct extent_path),
+                                   &handle->path);
        handle->path[0].buf = (char *) handle->inode->i_block;
 
        handle->path[0].left = handle->path[0].entries =
@@ -485,6 +485,13 @@ retry:
                        return retval;
                }
 
+               if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
+                   !ext2fs_extent_block_csum_verify(handle->fs, handle->ino,
+                                                    eh)) {
+                       handle->level--;
+                       return EXT2_ET_EXTENT_CSUM_INVALID;
+               }
+
                newpath->left = newpath->entries =
                        ext2fs_le16_to_cpu(eh->eh_entries);
                newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max);
@@ -571,6 +578,7 @@ static errcode_t update_path(ext2_extent_handle_t handle)
        blk64_t                         blk;
        errcode_t                       retval;
        struct ext3_extent_idx          *ix;
+       struct ext3_extent_header       *eh;
 
        if (handle->level == 0) {
                retval = ext2fs_write_inode(handle->fs, handle->ino,
@@ -580,6 +588,14 @@ static errcode_t update_path(ext2_extent_handle_t handle)
                blk = ext2fs_le32_to_cpu(ix->ei_leaf) +
                        ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32);
 
+               /* then update the checksum */
+               eh = (struct ext3_extent_header *)
+                               handle->path[handle->level].buf;
+               retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino,
+                                                     eh);
+               if (retval)
+                       return retval;
+
                retval = io_channel_write_blk64(handle->fs->io,
                                      blk, 1, handle->path[handle->level].buf);
        }
@@ -734,7 +750,14 @@ errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle,
  * and so on.
  *
  * Safe to call for any position in node; if not at the first entry,
- * will  simply return.
+ * it will simply return.
+ *
+ * Note a subtlety of this function -- if there happen to be two extents
+ * mapping the same lblk and someone calls fix_parents on the second of the two
+ * extents, the position of the extent handle after the call will be the second
+ * extent if nothing happened, or the first extent if something did.  A caller
+ * in this situation must use ext2fs_extent_goto() after calling this function.
+ * Or simply don't map the same lblk with two extents, ever.
  */
 errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle)
 {
@@ -954,13 +977,11 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle,
        if (handle->level == 0) {
                new_root = 1;
                tocopy = ext2fs_le16_to_cpu(eh->eh_entries);
-               retval = ext2fs_get_mem(((handle->max_depth+2) *
-                                        sizeof(struct extent_path)),
-                                       &newpath);
+               retval = ext2fs_get_memzero((handle->max_paths + 1) *
+                                           sizeof(struct extent_path),
+                                           &newpath);
                if (retval)
                        goto done;
-               memset(newpath, 0,
-                      ((handle->max_depth+2) * sizeof(struct extent_path)));
        } else {
                if (no_balance)
                        tocopy = 1;
@@ -1024,6 +1045,11 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle,
 
        new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block);
 
+       /* then update the checksum */
+       retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino, neweh);
+       if (retval)
+               goto done;
+
        /* ...and write the new node block out to disk. */
        retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1,
                                        block_buf);
@@ -1036,13 +1062,14 @@ static errcode_t extent_node_split(ext2_extent_handle_t handle,
        /* current path now has fewer active entries, we copied some out */
        if (handle->level == 0) {
                memcpy(newpath, path,
-                      sizeof(struct extent_path) * (handle->max_depth+1));
+                      sizeof(struct extent_path) * handle->max_paths);
                handle->path = newpath;
                newpath = path;
                path = handle->path;
                path->entries = 1;
                path->left = path->max_entries - 1;
                handle->max_depth++;
+               handle->max_paths++;
                eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth);
        } else {
                path->entries -= tocopy;
@@ -1424,17 +1451,25 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
                                                               &next_extent);
                                if (retval)
                                        goto done;
-                               retval = ext2fs_extent_fix_parents(handle);
-                               if (retval)
-                                       goto done;
                        } else
                                retval = ext2fs_extent_insert(handle,
                                      EXT2_EXTENT_INSERT_AFTER, &newextent);
                        if (retval)
                                goto done;
-                       /* Now pointing at inserted extent; move back to prev */
+                       retval = ext2fs_extent_fix_parents(handle);
+                       if (retval)
+                               goto done;
+                       /*
+                        * Now pointing at inserted extent; move back to prev.
+                        *
+                        * We cannot use EXT2_EXTENT_PREV to go back; note the
+                        * subtlety in the comment for fix_parents().
+                        */
+                       retval = ext2fs_extent_goto(handle, logical);
+                       if (retval)
+                               goto done;
                        retval = ext2fs_extent_get(handle,
-                                                  EXT2_EXTENT_PREV_LEAF,
+                                                  EXT2_EXTENT_CURRENT,
                                                   &extent);
                        if (retval)
                                goto done;
@@ -1467,6 +1502,9 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
                                                              0, &newextent);
                        if (retval)
                                goto done;
+                       retval = ext2fs_extent_fix_parents(handle);
+                       if (retval)
+                               goto done;
                        retval = ext2fs_extent_get(handle,
                                                   EXT2_EXTENT_NEXT_LEAF,
                                                   &extent);
@@ -1509,7 +1547,7 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
                        if (retval) {
                                r2 = ext2fs_extent_goto(handle, orig_lblk);
                                if (r2 == 0)
-                                       ext2fs_extent_replace(handle, 0,
+                                       (void)ext2fs_extent_replace(handle, 0,
                                                              &orig_extent);
                                goto done;
                        }
@@ -1525,11 +1563,12 @@ errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle,
                                r2 = ext2fs_extent_goto(handle,
                                                        newextent.e_lblk);
                                if (r2 == 0)
-                                       ext2fs_extent_delete(handle, 0);
+                                       (void)ext2fs_extent_delete(handle, 0);
                        }
                        r2 = ext2fs_extent_goto(handle, orig_lblk);
                        if (r2 == 0)
-                               ext2fs_extent_replace(handle, 0, &orig_extent);
+                               (void)ext2fs_extent_replace(handle, 0,
+                                                           &orig_extent);
                        goto done;
                }
        }