Index: linux-2.4.24/fs/ext3/extents.c
===================================================================
--- linux-2.4.24.orig/fs/ext3/extents.c 2003-01-30 13:24:37.000000000 +0300
-+++ linux-2.4.24/fs/ext3/extents.c 2004-01-28 20:01:16.000000000 +0300
-@@ -0,0 +1,2254 @@
++++ linux-2.4.24/fs/ext3/extents.c 2004-01-29 16:18:31.000000000 +0300
+@@ -0,0 +1,2302 @@
+/*
+ * Copyright (C) 2003 Alex Tomas <alex@clusterfs.com>
+ *
+ struct ext3_extents_tree *tree,
+ struct ext3_ext_path *path)
+{
++ int err;
++
+ if (path->p_bh) {
+ /* path points to block */
-+ return ext3_journal_get_write_access(handle, path->p_bh);
++ err = ext3_journal_get_write_access(handle, path->p_bh);
++ } else {
++ /* path points to leaf/index in inode body */
++ err = ext3_ext_get_access_for_root(handle, tree);
+ }
-+
-+ /* path points to leaf/index in inode body */
-+ return ext3_ext_get_access_for_root(handle, tree);
++ if (err)
++ printk("err=%d (%s:%d)\n", err, __FILE__, __LINE__);
++ return err;
+}
+
+/*
+static int ext3_ext_dirty(handle_t *handle, struct ext3_extents_tree *tree,
+ struct ext3_ext_path *path)
+{
++ int err;
+ if (path->p_bh) {
+ /* path points to block */
-+ return ext3_journal_dirty_metadata(handle, path->p_bh);
++ err =ext3_journal_dirty_metadata(handle, path->p_bh);
++ } else {
++ /* path points to leaf/index in inode body */
++ err = ext3_ext_mark_root_dirty(handle, tree);
+ }
-+
-+ /* path points to leaf/index in inode body */
-+ return ext3_ext_mark_root_dirty(handle, tree);
++ if (err)
++ printk("err=%d (%s:%d)\n", err, __FILE__, __LINE__);
++ return err;
+}
+
+static int inline
+ return newblock;
+}
+
++static inline void ext3_ext_tree_changed(struct ext3_extents_tree *tree)
++{
++ struct ext3_extent_header *neh;
++ neh = EXT_ROOT_HDR(tree);
++ neh->e_generation++;
++}
++
+static inline int ext3_ext_space_block(struct ext3_extents_tree *tree)
+{
+ int size;
+ path[depth].p_ext++;
+ while (path[depth].p_ext <=
+ EXT_MAX_EXTENT(path[depth].p_hdr)) {
-+ ext_debug(tree, "move %d:%d:%d in new leaf\n",
++ ext_debug(tree, "move %d:%d:%d in new leaf %lu\n",
+ path[depth].p_ext->e_block,
+ path[depth].p_ext->e_start,
-+ path[depth].p_ext->e_num);
++ path[depth].p_ext->e_num,
++ newblock);
+ memmove(ex++, path[depth].p_ext++,
+ sizeof(struct ext3_extent));
+ neh->e_num++;
+
+ /* correct old leaf */
+ if (m) {
-+ if ((err = ext3_ext_get_access(handle, tree, path)))
++ if ((err = ext3_ext_get_access(handle, tree, path + depth)))
+ goto cleanup;
+ path[depth].p_hdr->e_num -= m;
-+ if ((err = ext3_ext_dirty(handle, tree, path)))
++ if ((err = ext3_ext_dirty(handle, tree, path + depth)))
+ goto cleanup;
+
+ }
+ EXT_ASSERT(EXT_MAX_INDEX(path[i].p_hdr) ==
+ EXT_LAST_INDEX(path[i].p_hdr));
+ while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
-+ ext_debug(tree, "%d: move %d:%d in new index\n",
++ ext_debug(tree, "%d: move %d:%d in new index %lu\n",
+ i, path[i].p_idx->e_block,
-+ path[i].p_idx->e_leaf);
++ path[i].p_idx->e_leaf, newblock);
+ memmove(++fidx, path[i].p_idx++,
+ sizeof(struct ext3_extent_idx));
+ neh->e_num++;
+ return err;
+ ex->e_num += newext->e_num;
+ err = ext3_ext_dirty(handle, tree, path + depth);
-+ return err;
++ ext3_ext_tree_changed(tree);
++ goto out;
+ }
+
+repeat:
+ ext3_ext_drop_refs(npath);
+ kfree(npath);
+ }
-+
++out:
++ ext3_ext_tree_changed(tree);
+ return err;
+}
+
+ struct ext3_ext_path *path = NULL;
+ struct ext3_extent *ex, cbex;
+ unsigned long next, start = 0, end = 0;
++ unsigned long last = block + num;
+ int depth, exists, err = 0;
+
+ EXT_ASSERT(tree);
+ EXT_ASSERT(tree->inode);
+ EXT_ASSERT(tree->root);
+
-+ while (num > 0 && block != 0xfffffffff) {
++ while (block < last && block != 0xfffffffff) {
++ num = last - block;
+ /* find extent for this block */
+ path = ext3_ext_find_extent(tree, block, path);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
++ path = NULL;
+ break;
+ }
+
+ /* there is no extent yet, so try to allocate
+ * all requested space */
+ start = block;
-+ end = block + num - 1;
++ end = block + num;
+ } else if (ex->e_block > block) {
+ /* need to allocate space before found extent */
+ start = block;
-+ end = ex->e_block - 1;
-+ if (block + num - 1 < end)
-+ end = block + num - 1;
++ end = ex->e_block;
++ if (block + num < end)
++ end = block + num;
+ } else if (block >= ex->e_block + ex->e_num) {
+ /* need to allocate space after found extent */
+ start = block;
-+ end = block + num - 1;
++ end = block + num;
+ if (end >= next)
-+ end = next - 1;
++ end = next;
+ } else if (block >= ex->e_block) {
+ /*
+ * some part of requested space is covered
+ * by found extent
+ */
+ start = block;
-+ end = ex->e_block + ex->e_num - 1;
-+ if (block + num - 1 < end)
-+ end = block + num - 1;
++ end = ex->e_block + ex->e_num;
++ if (block + num < end)
++ end = block + num;
+ exists = 1;
+ } else {
+ BUG();
+ }
++ EXT_ASSERT(end > start);
+
+ if (!exists) {
+ cbex.e_block = start;
-+ cbex.e_num = end - start + 1;
++ cbex.e_num = end - start;
+ cbex.e_start = 0;
+ } else
+ cbex = *ex;
+
+ err = func(tree, path, &cbex, exists);
++ ext3_ext_drop_refs(path);
++
+ if (err < 0)
+ break;
-+
-+ if (err == EXT_BREAK) {
++ if (err == EXT_REPEAT)
++ continue;
++ else if (err == EXT_BREAK) {
+ err = 0;
+ break;
+ }
+
+ if (EXT_DEPTH(tree) != depth) {
+ /* depth was changed. we have to realloc path */
-+ ext3_ext_drop_refs(path);
+ kfree(path);
+ path = NULL;
+ }
+
-+ block += cbex.e_num;
-+ num -= cbex.e_num;
++ block = cbex.e_block + cbex.e_num;
+ }
+
+ if (path) {
+ err = ext3_ext_dirty(handle, tree, path);
+ }
+ }
++ ext3_ext_tree_changed(tree);
+
+ kfree(path);
+ ext3_journal_stop(handle, inode);
+static int ext3_mark_buffer_dirty(handle_t *handle, void *buffer)
+{
+ struct inode *inode = buffer;
-+ ext3_mark_inode_dirty(handle, inode);
-+ return 0;
++ return ext3_mark_inode_dirty(handle, inode);
+}
+
+static int ext3_ext_mergable(struct ext3_extent *ex1,
+ loff_t new_i_size;
+ handle_t *handle;
+ unsigned long pblock;
++ unsigned long tgen;
+
+ if (exist)
+ return EXT_CONTINUE;
+
++ tgen = EXT_GENERATION(tree);
+ count = ext3_ext_calc_credits_for_insert(tree, path);
++ up_write(&EXT3_I(inode)->truncate_sem);
++
+ handle = ext3_journal_start(inode, count + EXT3_ALLOC_NEEDED + 1);
-+ if (IS_ERR(handle))
++ if (IS_ERR(handle)) {
++ down_write(&EXT3_I(inode)->truncate_sem);
+ return PTR_ERR(handle);
++ }
+
++ if (tgen != EXT_GENERATION(tree)) {
++ /* the tree has changed. so path can be invalid at moment */
++ ext3_journal_stop(handle, inode);
++ down_write(&EXT3_I(inode)->truncate_sem);
++ return EXT_REPEAT;
++ }
++
++ down_write(&EXT3_I(inode)->truncate_sem);
+ goal = ext3_ext_find_goal(inode, path);
+ count = newex->e_num;
+ pblock = ext3_new_blocks(handle, inode, &count, goal, &err);
++ if (!pblock)
++ goto out;
+ EXT_ASSERT(count <= newex->e_num);
-+ /* FIXME: error handling here */
-+ EXT_ASSERT(err == 0);
+
+ /* insert new extent */
+ newex->e_start = pblock;
+ path = ext3_ext_find_extent(&tree, iblock, NULL);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
++ path = NULL;
+ goto out2;
+ }
+
+{
+ int err = 0;
+
++ if (!(EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL))
++ return -EINVAL;
++
+ if (cmd == EXT3_IOC_GET_EXTENTS) {
+ struct ext3_extent_buf buf;
+ struct ext3_extents_tree tree;
+ buf.cur = buf.buffer;
+ buf.err = 0;
+ tree.private = &buf;
++ down_write(&EXT3_I(inode)->truncate_sem);
+ err = ext3_ext_walk_space(&tree, buf.start, 0xffffffff,
+ ext3_ext_store_extent_cb);
++ up_write(&EXT3_I(inode)->truncate_sem);
+ if (err == 0)
+ err = buf.err;
+ } else if (cmd == EXT3_IOC_GET_TREE_STATS) {
+ struct ext3_extents_tree tree;
+
+ ext3_init_tree_desc(&tree, inode);
++ down_write(&EXT3_I(inode)->truncate_sem);
+ buf.depth = EXT_DEPTH(&tree);
+ buf.extents_num = 0;
+ buf.leaf_num = 0;
+ tree.private = &buf;
+ err = ext3_ext_walk_space(&tree, 0, 0xffffffff,
+ ext3_ext_collect_stats_cb);
++ up_write(&EXT3_I(inode)->truncate_sem);
+ if (!err)
+ err = copy_to_user((void *) arg, &buf, sizeof(buf));
+ } else if (cmd == EXT3_IOC_GET_TREE_DEPTH) {
+ struct ext3_extents_tree tree;
+ ext3_init_tree_desc(&tree, inode);
++ down_write(&EXT3_I(inode)->truncate_sem);
+ err = EXT_DEPTH(&tree);
++ up_write(&EXT3_I(inode)->truncate_sem);
+ }
+
+ return err;
Index: linux-2.4.24/include/linux/ext3_extents.h
===================================================================
--- linux-2.4.24.orig/include/linux/ext3_extents.h 2003-01-30 13:24:37.000000000 +0300
-+++ linux-2.4.24/include/linux/ext3_extents.h 2004-01-26 23:17:19.000000000 +0300
-@@ -0,0 +1,212 @@
++++ linux-2.4.24/include/linux/ext3_extents.h 2004-01-29 01:13:10.000000000 +0300
+@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2003 Alex Tomas <alex@clusterfs.com>
+ *
+#define EXT_STATS_
+
+
-+#define EXT3_ALLOC_NEEDED 2 /* block bitmap + group descriptor */
++#define EXT3_ALLOC_NEEDED 3 /* block bitmap + group desc. + sb */
+
+/*
+ * ext3_inode has i_block array (total 60 bytes)
+ __u16 e_num; /* number of valid entries */
+ __u16 e_max; /* capacity of store in entries */
+ __u16 e_depth; /* has tree real underlaying blocks? */
++ __u32 e_generation; /* generation of the tree */
+};
+
+#define EXT3_EXT_MAGIC 0xf301
+
+#define EXT_CONTINUE 0
+#define EXT_BREAK 1
++#define EXT_REPEAT 2
+
+
+#define EXT_FIRST_EXTENT(__hdr__) \
+ ((struct ext3_extent_header *) (bh)->b_data)
+#define EXT_DEPTH(_t_) \
+ (((struct ext3_extent_header *)((_t_)->root))->e_depth)
++#define EXT_GENERATION(_t_) \
++ (((struct ext3_extent_header *)((_t_)->root))->e_generation)
+
+
+#define EXT_ASSERT(__x__) if (!(__x__)) BUG();
Index: linux-2.4.21-suse2/fs/ext3/extents.c
===================================================================
--- linux-2.4.21-suse2.orig/fs/ext3/extents.c 2003-01-30 13:24:37.000000000 +0300
-+++ linux-2.4.21-suse2/fs/ext3/extents.c 2004-01-28 20:15:12.000000000 +0300
-@@ -0,0 +1,2255 @@
++++ linux-2.4.21-suse2/fs/ext3/extents.c 2004-01-29 16:27:55.000000000 +0300
+@@ -0,0 +1,2303 @@
+/*
+ * Copyright (C) 2003 Alex Tomas <alex@clusterfs.com>
+ *
+ struct ext3_extents_tree *tree,
+ struct ext3_ext_path *path)
+{
++ int err;
++
+ if (path->p_bh) {
+ /* path points to block */
-+ return ext3_journal_get_write_access(handle, path->p_bh);
++ err = ext3_journal_get_write_access(handle, path->p_bh);
++ } else {
++ /* path points to leaf/index in inode body */
++ err = ext3_ext_get_access_for_root(handle, tree);
+ }
-+
-+ /* path points to leaf/index in inode body */
-+ return ext3_ext_get_access_for_root(handle, tree);
++ if (err)
++ printk("err=%d (%s:%d)\n", err, __FILE__, __LINE__);
++ return err;
+}
+
+/*
+static int ext3_ext_dirty(handle_t *handle, struct ext3_extents_tree *tree,
+ struct ext3_ext_path *path)
+{
++ int err;
+ if (path->p_bh) {
+ /* path points to block */
-+ return ext3_journal_dirty_metadata(handle, path->p_bh);
++ err =ext3_journal_dirty_metadata(handle, path->p_bh);
++ } else {
++ /* path points to leaf/index in inode body */
++ err = ext3_ext_mark_root_dirty(handle, tree);
+ }
-+
-+ /* path points to leaf/index in inode body */
-+ return ext3_ext_mark_root_dirty(handle, tree);
++ if (err)
++ printk("err=%d (%s:%d)\n", err, __FILE__, __LINE__);
++ return err;
+}
+
+static int inline
+ return newblock;
+}
+
++static inline void ext3_ext_tree_changed(struct ext3_extents_tree *tree)
++{
++ struct ext3_extent_header *neh;
++ neh = EXT_ROOT_HDR(tree);
++ neh->e_generation++;
++}
++
+static inline int ext3_ext_space_block(struct ext3_extents_tree *tree)
+{
+ int size;
+ path[depth].p_ext++;
+ while (path[depth].p_ext <=
+ EXT_MAX_EXTENT(path[depth].p_hdr)) {
-+ ext_debug(tree, "move %d:%d:%d in new leaf\n",
++ ext_debug(tree, "move %d:%d:%d in new leaf %lu\n",
+ path[depth].p_ext->e_block,
+ path[depth].p_ext->e_start,
-+ path[depth].p_ext->e_num);
++ path[depth].p_ext->e_num,
++ newblock);
+ memmove(ex++, path[depth].p_ext++,
+ sizeof(struct ext3_extent));
+ neh->e_num++;
+
+ /* correct old leaf */
+ if (m) {
-+ if ((err = ext3_ext_get_access(handle, tree, path)))
++ if ((err = ext3_ext_get_access(handle, tree, path + depth)))
+ goto cleanup;
+ path[depth].p_hdr->e_num -= m;
-+ if ((err = ext3_ext_dirty(handle, tree, path)))
++ if ((err = ext3_ext_dirty(handle, tree, path + depth)))
+ goto cleanup;
+
+ }
+ EXT_ASSERT(EXT_MAX_INDEX(path[i].p_hdr) ==
+ EXT_LAST_INDEX(path[i].p_hdr));
+ while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
-+ ext_debug(tree, "%d: move %d:%d in new index\n",
++ ext_debug(tree, "%d: move %d:%d in new index %lu\n",
+ i, path[i].p_idx->e_block,
-+ path[i].p_idx->e_leaf);
++ path[i].p_idx->e_leaf, newblock);
+ memmove(++fidx, path[i].p_idx++,
+ sizeof(struct ext3_extent_idx));
+ neh->e_num++;
+ return err;
+ ex->e_num += newext->e_num;
+ err = ext3_ext_dirty(handle, tree, path + depth);
-+ return err;
++ ext3_ext_tree_changed(tree);
++ goto out;
+ }
+
+repeat:
+ ext3_ext_drop_refs(npath);
+ kfree(npath);
+ }
-+
++out:
++ ext3_ext_tree_changed(tree);
+ return err;
+}
+
+ struct ext3_ext_path *path = NULL;
+ struct ext3_extent *ex, cbex;
+ unsigned long next, start = 0, end = 0;
++ unsigned long last = block + num;
+ int depth, exists, err = 0;
+
+ EXT_ASSERT(tree);
+ EXT_ASSERT(tree->inode);
+ EXT_ASSERT(tree->root);
+
-+ while (num > 0 && block != 0xfffffffff) {
++ while (block < last && block != 0xfffffffff) {
++ num = last - block;
+ /* find extent for this block */
+ path = ext3_ext_find_extent(tree, block, path);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
++ path = NULL;
+ break;
+ }
+
+ /* there is no extent yet, so try to allocate
+ * all requested space */
+ start = block;
-+ end = block + num - 1;
++ end = block + num;
+ } else if (ex->e_block > block) {
+ /* need to allocate space before found extent */
+ start = block;
-+ end = ex->e_block - 1;
-+ if (block + num - 1 < end)
-+ end = block + num - 1;
++ end = ex->e_block;
++ if (block + num < end)
++ end = block + num;
+ } else if (block >= ex->e_block + ex->e_num) {
+ /* need to allocate space after found extent */
+ start = block;
-+ end = block + num - 1;
++ end = block + num;
+ if (end >= next)
-+ end = next - 1;
++ end = next;
+ } else if (block >= ex->e_block) {
+ /*
+ * some part of requested space is covered
+ * by found extent
+ */
+ start = block;
-+ end = ex->e_block + ex->e_num - 1;
-+ if (block + num - 1 < end)
-+ end = block + num - 1;
++ end = ex->e_block + ex->e_num;
++ if (block + num < end)
++ end = block + num;
+ exists = 1;
+ } else {
+ BUG();
+ }
++ EXT_ASSERT(end > start);
+
+ if (!exists) {
+ cbex.e_block = start;
-+ cbex.e_num = end - start + 1;
++ cbex.e_num = end - start;
+ cbex.e_start = 0;
+ } else
+ cbex = *ex;
+
+ err = func(tree, path, &cbex, exists);
++ ext3_ext_drop_refs(path);
++
+ if (err < 0)
+ break;
-+
-+ if (err == EXT_BREAK) {
++ if (err == EXT_REPEAT)
++ continue;
++ else if (err == EXT_BREAK) {
+ err = 0;
+ break;
+ }
+
+ if (EXT_DEPTH(tree) != depth) {
+ /* depth was changed. we have to realloc path */
-+ ext3_ext_drop_refs(path);
+ kfree(path);
+ path = NULL;
+ }
+
-+ block += cbex.e_num;
-+ num -= cbex.e_num;
++ block = cbex.e_block + cbex.e_num;
+ }
+
+ if (path) {
+ err = ext3_ext_dirty(handle, tree, path);
+ }
+ }
++ ext3_ext_tree_changed(tree);
+
+ kfree(path);
+ ext3_journal_stop(handle, inode);
+static int ext3_mark_buffer_dirty(handle_t *handle, void *buffer)
+{
+ struct inode *inode = buffer;
-+ ext3_mark_inode_dirty(handle, inode);
-+ return 0;
++ return ext3_mark_inode_dirty(handle, inode);
+}
+
+static int ext3_ext_mergable(struct ext3_extent *ex1,
+ loff_t new_i_size;
+ handle_t *handle;
+ unsigned long pblock;
++ unsigned long tgen;
+
+ if (exist)
+ return EXT_CONTINUE;
+
++ tgen = EXT_GENERATION(tree);
+ count = ext3_ext_calc_credits_for_insert(tree, path);
++ up_write(&EXT3_I(inode)->truncate_sem);
++
+ handle = ext3_journal_start(inode, count + EXT3_ALLOC_NEEDED + 1);
-+ if (IS_ERR(handle))
++ if (IS_ERR(handle)) {
++ down_write(&EXT3_I(inode)->truncate_sem);
+ return PTR_ERR(handle);
++ }
+
++ if (tgen != EXT_GENERATION(tree)) {
++ /* the tree has changed. so path can be invalid at moment */
++ ext3_journal_stop(handle, inode);
++ down_write(&EXT3_I(inode)->truncate_sem);
++ return EXT_REPEAT;
++ }
++
++ down_write(&EXT3_I(inode)->truncate_sem);
+ goal = ext3_ext_find_goal(inode, path);
+ count = newex->e_num;
+ pblock = ext3_new_blocks(handle, inode, &count, goal, &err);
++ if (!pblock)
++ goto out;
+ EXT_ASSERT(count <= newex->e_num);
-+ /* FIXME: error handling here */
-+ EXT_ASSERT(err == 0);
+
+ /* insert new extent */
+ newex->e_start = pblock;
+ path = ext3_ext_find_extent(&tree, iblock, NULL);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
++ path = NULL;
+ goto out2;
+ }
+
+{
+ int err = 0;
+
++ if (!(EXT3_I(inode)->i_flags & EXT3_EXTENTS_FL))
++ return -EINVAL;
++
+ if (cmd == EXT3_IOC_GET_EXTENTS) {
+ struct ext3_extent_buf buf;
+ struct ext3_extents_tree tree;
+ buf.cur = buf.buffer;
+ buf.err = 0;
+ tree.private = &buf;
++ down_write(&EXT3_I(inode)->truncate_sem);
+ err = ext3_ext_walk_space(&tree, buf.start, 0xffffffff,
+ ext3_ext_store_extent_cb);
++ up_write(&EXT3_I(inode)->truncate_sem);
+ if (err == 0)
+ err = buf.err;
+ } else if (cmd == EXT3_IOC_GET_TREE_STATS) {
+ struct ext3_extents_tree tree;
+
+ ext3_init_tree_desc(&tree, inode);
++ down_write(&EXT3_I(inode)->truncate_sem);
+ buf.depth = EXT_DEPTH(&tree);
+ buf.extents_num = 0;
+ buf.leaf_num = 0;
+ tree.private = &buf;
+ err = ext3_ext_walk_space(&tree, 0, 0xffffffff,
+ ext3_ext_collect_stats_cb);
++ up_write(&EXT3_I(inode)->truncate_sem);
+ if (!err)
+ err = copy_to_user((void *) arg, &buf, sizeof(buf));
+ } else if (cmd == EXT3_IOC_GET_TREE_DEPTH) {
+ struct ext3_extents_tree tree;
+ ext3_init_tree_desc(&tree, inode);
++ down_write(&EXT3_I(inode)->truncate_sem);
+ err = EXT_DEPTH(&tree);
++ up_write(&EXT3_I(inode)->truncate_sem);
+ }
+
+ return err;
Index: linux-2.4.21-suse2/include/linux/ext3_extents.h
===================================================================
--- linux-2.4.21-suse2.orig/include/linux/ext3_extents.h 2003-01-30 13:24:37.000000000 +0300
-+++ linux-2.4.21-suse2/include/linux/ext3_extents.h 2004-01-24 20:10:25.000000000 +0300
-@@ -0,0 +1,212 @@
++++ linux-2.4.21-suse2/include/linux/ext3_extents.h 2004-01-29 15:35:26.000000000 +0300
+@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2003 Alex Tomas <alex@clusterfs.com>
+ *
+#define EXT_STATS_
+
+
-+#define EXT3_ALLOC_NEEDED 2 /* block bitmap + group descriptor */
++#define EXT3_ALLOC_NEEDED 3 /* block bitmap + group desc. + sb */
+
+/*
+ * ext3_inode has i_block array (total 60 bytes)
+ __u16 e_num; /* number of valid entries */
+ __u16 e_max; /* capacity of store in entries */
+ __u16 e_depth; /* has tree real underlaying blocks? */
++ __u32 e_generation; /* generation of the tree */
+};
+
+#define EXT3_EXT_MAGIC 0xf301
+
+#define EXT_CONTINUE 0
+#define EXT_BREAK 1
++#define EXT_REPEAT 2
+
+
+#define EXT_FIRST_EXTENT(__hdr__) \
+ ((struct ext3_extent_header *) (bh)->b_data)
+#define EXT_DEPTH(_t_) \
+ (((struct ext3_extent_header *)((_t_)->root))->e_depth)
++#define EXT_GENERATION(_t_) \
++ (((struct ext3_extent_header *)((_t_)->root))->e_generation)
+
+
+#define EXT_ASSERT(__x__) if (!(__x__)) BUG();