Whamcloud - gitweb
- locking reworked in ext3_ext_new_extent_cb(). this change solved
authoralex <alex>
Thu, 29 Jan 2004 13:35:38 +0000 (13:35 +0000)
committeralex <alex>
Thu, 29 Jan 2004 13:35:38 +0000 (13:35 +0000)
  possible deadlock
- locking in extent's ioctl added
- ext3_ext_walk_space() drops bh's references in path before finding
  next extent

NOTE: dbench and syntetic tests work OK in vmware for many hours

lustre/kernel_patches/patches/ext3-extents-2.4.20.patch
lustre/kernel_patches/patches/ext3-extents-2.4.21-suse2.patch

index f2108d0..8916f0f 100644 (file)
@@ -1,8 +1,8 @@
 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>
 + *
@@ -88,13 +88,18 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +                              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;
 +}
 +
 +/*
@@ -106,13 +111,17 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +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
@@ -148,6 +157,13 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +      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;
@@ -614,10 +630,11 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +      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++;
@@ -633,10 +650,10 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +
 +      /* 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;
 +              
 +      }
@@ -682,9 +699,9 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +              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++;
@@ -1041,7 +1058,8 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +                      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:
@@ -1137,7 +1155,8 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +              ext3_ext_drop_refs(npath);
 +              kfree(npath);
 +      }
-+              
++out:  
++      ext3_ext_tree_changed(tree);
 +      return err;
 +}
 +
@@ -1147,6 +1166,7 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +      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);
@@ -1154,11 +1174,13 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +      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;
 +              }
 +
@@ -1171,58 +1193,60 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +                      /* 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) {
@@ -1724,6 +1748,7 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +                      err = ext3_ext_dirty(handle, tree, path);
 +              }
 +      }
++      ext3_ext_tree_changed(tree);
 +
 +      kfree(path);
 +      ext3_journal_stop(handle, inode);
@@ -1772,8 +1797,7 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +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,
@@ -1914,21 +1938,35 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +      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;
@@ -2004,6 +2042,7 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +      path = ext3_ext_find_extent(&tree, iblock, NULL);
 +      if (IS_ERR(path)) {
 +              err = PTR_ERR(path);
++              path = NULL;
 +              goto out2;
 +      }
 +
@@ -2220,6 +2259,9 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +{
 +      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;
@@ -2231,8 +2273,10 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +              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) {
@@ -2240,18 +2284,22 @@ Index: linux-2.4.24/fs/ext3/extents.c
 +              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;
@@ -2479,8 +2527,8 @@ Index: linux-2.4.24/include/linux/ext3_fs.h
 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>
 + *
@@ -2537,7 +2585,7 @@ Index: linux-2.4.24/include/linux/ext3_extents.h
 +#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)
@@ -2574,6 +2622,7 @@ Index: linux-2.4.24/include/linux/ext3_extents.h
 +      __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
@@ -2634,6 +2683,7 @@ Index: linux-2.4.24/include/linux/ext3_extents.h
 +
 +#define EXT_CONTINUE  0
 +#define EXT_BREAK     1
++#define EXT_REPEAT    2
 +
 +
 +#define EXT_FIRST_EXTENT(__hdr__) \
@@ -2659,6 +2709,8 @@ Index: linux-2.4.24/include/linux/ext3_extents.h
 +      ((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 01f1152..42f39f7 100644 (file)
@@ -1,8 +1,8 @@
 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>
 + *
@@ -88,13 +88,18 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +                              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;
 +}
 +
 +/*
@@ -106,13 +111,17 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +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
@@ -148,6 +157,13 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +      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;
@@ -614,10 +630,11 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +      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++;
@@ -633,10 +650,10 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +
 +      /* 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;
 +              
 +      }
@@ -682,9 +699,9 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +              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++;
@@ -1041,7 +1058,8 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +                      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:
@@ -1137,7 +1155,8 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +              ext3_ext_drop_refs(npath);
 +              kfree(npath);
 +      }
-+              
++out:  
++      ext3_ext_tree_changed(tree);
 +      return err;
 +}
 +
@@ -1147,6 +1166,7 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +      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);
@@ -1154,11 +1174,13 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +      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;
 +              }
 +
@@ -1171,58 +1193,60 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +                      /* 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) {
@@ -1724,6 +1748,7 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +                      err = ext3_ext_dirty(handle, tree, path);
 +              }
 +      }
++      ext3_ext_tree_changed(tree);
 +
 +      kfree(path);
 +      ext3_journal_stop(handle, inode);
@@ -1772,8 +1797,7 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +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,
@@ -1914,21 +1938,35 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +      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;
@@ -2005,6 +2043,7 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +      path = ext3_ext_find_extent(&tree, iblock, NULL);
 +      if (IS_ERR(path)) {
 +              err = PTR_ERR(path);
++              path = NULL;
 +              goto out2;
 +      }
 +
@@ -2221,6 +2260,9 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +{
 +      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;
@@ -2232,8 +2274,10 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +              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) {
@@ -2241,18 +2285,22 @@ Index: linux-2.4.21-suse2/fs/ext3/extents.c
 +              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;
@@ -2488,8 +2536,8 @@ Index: linux-2.4.21-suse2/include/linux/ext3_fs.h
 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>
 + *
@@ -2546,7 +2594,7 @@ Index: linux-2.4.21-suse2/include/linux/ext3_extents.h
 +#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)
@@ -2583,6 +2631,7 @@ Index: linux-2.4.21-suse2/include/linux/ext3_extents.h
 +      __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
@@ -2643,6 +2692,7 @@ Index: linux-2.4.21-suse2/include/linux/ext3_extents.h
 +
 +#define EXT_CONTINUE  0
 +#define EXT_BREAK     1
++#define EXT_REPEAT    2
 +
 +
 +#define EXT_FIRST_EXTENT(__hdr__) \
@@ -2668,6 +2718,8 @@ Index: linux-2.4.21-suse2/include/linux/ext3_extents.h
 +      ((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();