#include "ext2fsP.h"
#include "e2image.h"
+#undef DEBUG
+
/*
* Definitions to be dropped in lib/ext2fs/ext2fs.h
*/
}
+static void dump_path(const char *tag, struct ext2_extent_handle *handle,
+ struct extent_path *path)
+{
+ struct extent_path *ppp = path;
+ printf("%s: level=%d\n", tag, handle->level);
+
+ do {
+ printf("%s: path=%ld buf=%p entries=%d max_entries=%d left=%d "
+ "visit_num=%d flags=0x%x end_blk=%llu curr=%p(%ld)\n",
+ tag, (ppp - handle->path), ppp->buf, ppp->entries,
+ ppp->max_entries, ppp->left, ppp->visit_num, ppp->flags,
+ ppp->end_blk, ppp->curr, ppp->curr - (void *)ppp->buf);
+ printf(" ");
+ dbg_show_header((struct ext3_extent_header *)ppp->buf);
+ if (ppp->curr) {
+ printf(" ");
+ dbg_show_index(ppp->curr);
+ printf(" ");
+ dbg_show_extent(ppp->curr);
+ }
+ ppp--;
+ } while (ppp >= handle->path);
+ fflush(stdout);
+
+ return;
+}
+
#else
#define dbg_show_header(eh) do { } while (0)
#define dbg_show_index(ix) do { } while (0)
#define dbg_show_extent(ex) do { } while (0)
#define dbg_print_extent(desc, ex) do { } while (0)
+#define dump_path(tag, handle, path) do { } while (0)
#endif
/*
return 0;
}
+static int splitting_at_eof(struct ext2_extent_handle *handle,
+ struct extent_path *path)
+{
+ struct extent_path *ppp = path;
+ dump_path(__func__, handle, path);
+
+ if (handle->level == 0)
+ return 0;
+
+ do {
+ if (ppp->left)
+ return 0;
+ ppp--;
+ } while (ppp >= handle->path);
+
+ return 1;
+}
+
/*
* allocate a new block, move half the current node to it, and update parent
*
* handle will be left pointing at original record.
*/
-errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle)
+static errcode_t extent_node_split(ext2_extent_handle_t handle,
+ int expand_allowed)
{
errcode_t retval = 0;
blk64_t new_node_pblk;
int tocopy;
int new_root = 0;
struct ext2_extent_info info;
+ int no_balance;
/* basic sanity */
EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE);
goto done;
goal_blk = extent.e_pblk;
- retval = ext2fs_extent_node_split(handle);
+ retval = extent_node_split(handle, expand_allowed);
if (retval)
goto done;
if (!path->curr)
return EXT2_ET_NO_CURRENT_NODE;
+ /*
+ * Normally, we try to split a full node in half. This doesn't turn
+ * out so well if we're tacking extents on the end of the file because
+ * then we're stuck with a tree of half-full extent blocks. This of
+ * course doesn't apply to the root level.
+ */
+ no_balance = expand_allowed ? splitting_at_eof(handle, path) : 0;
+
/* extent header of the current node we'll split */
eh = (struct ext3_extent_header *)path->buf;
memset(newpath, 0,
((handle->max_depth+2) * sizeof(struct extent_path)));
} else {
- tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2;
+ if (no_balance)
+ tocopy = 1;
+ else
+ tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2;
}
#ifdef DEBUG
handle->level);
#endif
- if (!tocopy) {
+ if (!tocopy && !no_balance) {
#ifdef DEBUG
printf("Nothing to copy to new block!\n");
#endif
goto done;
/* new node hooked in, so update inode block count (do this here?) */
- handle->inode->i_blocks += (handle->fs->blocksize *
- EXT2FS_CLUSTER_RATIO(handle->fs)) / 512;
+ ext2fs_iblk_add_blocks(handle->fs, handle->inode, 1);
retval = ext2fs_write_inode(handle->fs, handle->ino,
handle->inode);
if (retval)
return retval;
}
+errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle)
+{
+ return extent_node_split(handle, 0);
+}
+
errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags,
struct ext2fs_extent *extent)
{
printf("node full (level %d) - splitting\n",
handle->level);
#endif
- retval = ext2fs_extent_node_split(handle);
+ retval = extent_node_split(handle, 1);
if (retval)
return retval;
path = handle->path + handle->level;