Whamcloud - gitweb
Add more obvious error message after a patch failure, instead of before.
[fs/lustre-release.git] / lustre / extN / htree-ext3-2.4.18.diff
index 7ce54f4..936ff8f 100644 (file)
@@ -1,23 +1,3 @@
---- ./fs/ext3/dir.c    2002/03/05 06:18:59     2.1
-+++ ./fs/ext3/dir.c    2002/03/05 06:26:56
-@@ -26,7 +26,7 @@
-       DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
- };
--static int ext3_readdir(struct file *, void *, filldir_t);
-+int ext3_readdir(struct file *, void *, filldir_t);
- struct file_operations ext3_dir_operations = {
-       read:           generic_read_dir,
-@@ -65,7 +65,7 @@
-       return error_msg == NULL ? 1 : 0;
- }
--static int ext3_readdir(struct file * filp,
-+int ext3_readdir(struct file * filp,
-                        void * dirent, filldir_t filldir)
- {
-       int error = 0;
 --- ./fs/ext3/super.c  2002/03/05 06:18:59     2.1
 +++ ./fs/ext3/super.c  2002/03/05 06:26:56
 @@ -529,6 +529,12 @@
                else if (!strcmp (this_char, "debug"))
                        set_opt (*mount_options, DEBUG);
                else if (!strcmp (this_char, "errors")) {
-@@ -712,6 +718,10 @@
-                       EXT3_BLOCKS_PER_GROUP(sb),
-                       EXT3_INODES_PER_GROUP(sb),
-                       sbi->s_mount_opt);
-+
-+      if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX))
+@@ -702,6 +708,12 @@ static int ext3_setup_super(struct super
+       es->s_mtime = cpu_to_le32(CURRENT_TIME);
+       ext3_update_dynamic_rev(sb);
+       EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);
++
++      if (test_opt(sb, INDEX))
++              EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX);
++      else if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX))
 +              set_opt (EXT3_SB(sb)->s_mount_opt, INDEX);
 +
-       printk(KERN_INFO "EXT3 FS " EXT3FS_VERSION ", " EXT3FS_DATE " on %s, ",
-                               bdevname(sb->s_dev));
-       if (EXT3_SB(sb)->s_journal->j_inode == NULL) {
+       ext3_commit_super (sb, es, 1);
+       if (test_opt (sb, DEBUG))
+               printk (KERN_INFO
 --- ./fs/ext3/namei.c  2002/03/05 06:18:59     2.1
 +++ ./fs/ext3/namei.c  2002/03/06 00:13:18
 @@ -16,6 +16,10 @@
   */
  
  #include <linux/fs.h>
-@@ -38,6 +42,438 @@
+@@ -33,7 +33,7 @@
+ #include <linux/string.h>
+ #include <linux/locks.h>
+ #include <linux/quotaops.h>
+-
++#include <linux/slab.h>
+ /*
+  * define how far ahead to read directories while searching them.
+@@ -38,6 +42,432 @@
  #define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
  #define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
  
-+void ext3_add_compat_feature (struct super_block *sb, unsigned feature)
-+{
-+      if (!EXT3_HAS_COMPAT_FEATURE(sb, feature))
-+      {
-+              lock_super(sb);
-+              ext3_update_dynamic_rev(sb);
-+              EXT3_SET_COMPAT_FEATURE(sb, feature);
-+              ext3_write_super(sb);
-+              unlock_super(sb);
-+      }
-+}
-+
 +static struct buffer_head *ext3_append(handle_t *handle,
 +                                      struct inode *inode,
 +                                      u32 *block, int *err)
@@ -90,7 +69,7 @@
 +}
 +
 +#ifndef assert
-+#define assert(test) do if (!(test)) BUG(); while (0)
++#define assert(test) J_ASSERT(test)
 +#endif
 +
 +#ifndef swap
 +
 +struct dx_root
 +{
-+      struct fake_dirent fake1;
-+      char dot1[4];
-+      struct fake_dirent fake2;
-+      char dot2[4];
++      struct fake_dirent dot;
++      char dot_name[4];
++      struct fake_dirent dotdot;
++      char dotdot_name[4];
 +      struct dx_root_info
 +      {
 +              le_u32 reserved_zero;
 +
 +static inline unsigned dx_get_block (struct dx_entry *entry)
 +{
-+      return le32_to_cpu(entry->block.v) & 0x0fffffff;
++      return le32_to_cpu(entry->block.v) & 0x00ffffff;
 +}
 +
 +static inline void dx_set_block (struct dx_entry *entry, unsigned value)
 +
 +static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
 +{
-+      unsigned entry_space = dir->i_sb->s_blocksize - 24 - infosize;
++      unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) -
++              EXT3_DIR_REC_LEN(2) - infosize;
 +      return 0? 20: entry_space / sizeof(struct dx_entry);
 +}
 +
 +static inline unsigned dx_node_limit (struct inode *dir)
 +{
-+      unsigned entry_space = dir->i_sb->s_blocksize - sizeof(struct fake_dirent);
++      unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0);
 +      return 0? 22: entry_space / sizeof(struct dx_entry);
 +}
 +
 +              hash1 = hash0;
 +              hash0 = hash;
 +      }
-+      return 80; /* FIXME: for test only */
 +      return hash0;
 +}
 +
 +      return (struct stats) { names, space, bcount};
 +}
 +
-+static void dx_show_buckets (struct inode *dir)
-+{
-+      struct buffer_head *bh;
-+      struct dx_root *root;
-+      int err;
-+      if (!(bh = ext3_bread (NULL,dir, 0, 0,&err))) return;
-+      root = (struct dx_root *) bh->b_data;
-+      dx_show_entries (dir, root->entries, root->info.indirect_levels);
-+      brelse (bh);
-+}
-+
-+ssize_t hack_show_dir (struct file * filp, void * dirent, filldir_t filldir)
-+{
-+      if (is_dx (filp->f_dentry->d_inode) && !filp->f_pos)
-+              dx_show_buckets (filp->f_dentry->d_inode);
-+      return ext3_readdir(filp,dirent,filldir);
-+}
-+
 +/*
 + * Probe for a directory leaf block to search
 + */
 +
-+static struct dx_frame *dx_probe (struct inode *dir, u32 hash, struct dx_frame *frame)
++static struct dx_frame *
++dx_probe(struct inode *dir, u32 hash, struct dx_frame *frame_in)
 +{
 +      unsigned count, indirect;
 +      struct dx_entry *at, *entries, *p, *q, *m;
 +      struct dx_root *root;
 +      struct buffer_head *bh;
++      struct dx_frame *frame = frame_in;
 +      int err;
-+      if (!(bh = ext3_bread (NULL,dir, 0, 0,&err)))
++
++      frame->bh = NULL;
++      if (!(bh = ext3_bread(NULL, dir, 0, 0, &err)))
 +              goto fail;
 +      root = (struct dx_root *) bh->b_data;
-+      if (root->info.hash_version > 0 || root->info.unused_flags & 1)
++      if (root->info.hash_version > 0 || root->info.unused_flags & 1) {
++              brelse(bh);
 +              goto fail;
-+      if ((indirect = root->info.indirect_levels) > 1)
++      }
++      if ((indirect = root->info.indirect_levels) > 1) {
++              brelse(bh);
 +              goto fail;
++      }
 +      entries = (struct dx_entry *) (((char *) &root->info) + root->info.info_length);
 +      assert (dx_get_limit(entries) == dx_root_limit(dir, root->info.info_length));
 +      dxtrace (printk("Look up %x", hash));
 +              frame++;
 +      }
 +fail2:
-+      brelse(frame->bh);
++      while (frame >= frame_in) {
++              brelse(frame->bh);
++              frame--;
++      }
 +fail:
 +      return NULL;
 +}
 +
 +static void dx_release (struct dx_frame *frames)
 +{
-+      if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)
++      if (frames[0].bh == NULL)
++              return;
++
++      if (((struct dx_root *)frames[0].bh->b_data)->info.indirect_levels)
 +              brelse (frames[1].bh);
 +      brelse (frames[0].bh);
 +}
 +      } while(more);
 +}
 +
-+static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block)
++static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
 +{
-+      struct dx_entry *entries = frame->entries, *at = frame->at;
-+      assert (dx_get_count (entries) < dx_get_limit (entries));
-+      memmove (at + 2, at+1, (char *) (entries + dx_get_count(entries)) - (char *) (at));
-+      dx_set_hash(at + 1, hash);
-+      dx_set_block(at + 1, block);
-+      dx_set_count(entries, dx_get_count(entries) + 1);
++      struct dx_entry *entries = frame->entries;
++      struct dx_entry *old = frame->at, *new = old + 1;
++      int count = dx_get_count(entries);
++
++      assert(count < dx_get_limit(entries));
++      assert(old < entries + count);
++      memmove(new + 1, new, (char *)(entries + count) - (char *)(new));
++      dx_set_hash(new, hash);
++      dx_set_block(new, block);
++      dx_set_count(entries, count + 1);
 +}
 +#endif
 +
++static void ext3_update_dx_flag(struct inode *inode)
++{
++      if (!test_opt(inode->i_sb, INDEX))
++              EXT3_I(inode)->i_flags &= ~EXT3_INDEX_FL;
++}
++
  /*
   * NOTE! unlike strncmp, ext3_match returns 1 for success, 0 for failure.
   *
 +              block = dx_get_block(frame->at);
 +              if (!(bh = ext3_bread (NULL,dir, block, 0, &err)))
 +                      goto dxfail;
-+              de = (struct ext3_dir_entry_2 *) bh->b_data;
-+              top = (struct ext3_dir_entry_2 *) ((char *) de + blocksize
-+                              EXT3_DIR_REC_LEN(0));
++              de = (ext3_dirent *) bh->b_data;
++              top = (ext3_dirent *) ((char *) de + blocksize -
++                              EXT3_DIR_REC_LEN(0));
 +              for (; de < top; de = ext3_next_entry(de))
 +                      if (ext3_match (namelen, name, de)) {
 +                              if (!ext3_check_dir_entry("ext3_find_entry",
        nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb);
        start = dir->u.ext3_i.i_dir_start_lookup;
        if (start >= nblocks)
-@@ -237,6 +748,88 @@
+@@ -237,6 +748,92 @@
                de->file_type = ext3_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
  }
  
 +      u32 newblock;
 +      unsigned MAX_DX_MAP = PAGE_CACHE_SIZE/EXT3_DIR_REC_LEN(1) + 1;
 +      u32 hash2;
-+      struct dx_map_entry map[MAX_DX_MAP];
++      struct dx_map_entry *map;
 +      char *data1 = (*bh)->b_data, *data2, *data3;
 +      unsigned split;
 +      ext3_dirent *de, *de2;
 +
 +      data2 = bh2->b_data;
 +
++      map = kmalloc(sizeof(*map) * MAX_DX_MAP, GFP_KERNEL);
++      if (!map)
++              panic("no memory for do_split\n");
 +      count = dx_make_map ((ext3_dirent *) data1, blocksize, map);
 +      split = count/2; // need to adjust to actual middle
 +      dx_sort_map (map, count);
 +      brelse (bh2);
 +      ext3_journal_dirty_metadata (handle, frame->bh);
 +      dxtrace(dx_show_index ("frame", frame->entries));
++      kfree(map);
 +      return de;
 +}
 +#endif
  static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
        struct inode *inode)
  {
-@@ -258,117 +852,284 @@
+@@ -258,117 +852,281 @@
        const char *name = dentry->d_name.name;
        int namelen = dentry->d_name.len;
        unsigned long offset;
 -      unsigned short rec_len;
        struct buffer_head * bh;
-       struct ext3_dir_entry_2 * de, * de1;
+-      struct ext3_dir_entry_2 * de, * de1;
 -      struct super_block * sb;
++      ext3_dirent *de;
 +      struct super_block * sb = dir->i_sb;
        int     retval;
 +      unsigned short reclen = EXT3_DIR_REC_LEN(namelen);
 -      sb = dir->i_sb;
 +      unsigned blocksize = sb->s_blocksize;
 +      unsigned nlen, rlen;
-+      u32 block;
++      u32 block, blocks;
 +      char *top;
  
        if (!namelen)
 -                              if (dir->i_size == 0) {
 -                                      brelse(bh);
 -                                      return -ENOENT;
-+      if (ext3_dx && is_dx(dir))
-+      {
++      if (ext3_dx && is_dx(dir)) {
 +              struct dx_frame frames[2], *frame;
 +              struct dx_entry *entries, *at;
 +              u32 hash;
 +              char *data1;
 +
-+              hash = dx_hash (name, namelen);
-+              frame = dx_probe (dir, hash, frames); // do something if null
++              hash = dx_hash(name, namelen);
++              /* FIXME: do something if dx_probe() fails here */
++              frame = dx_probe(dir, hash, frames);
 +              entries = frame->entries;
 +              at = frame->at;
 +
-+              if (!(bh = ext3_bread (handle,dir, dx_get_block(frame->at), 0,&retval)))
++              if (!(bh = ext3_bread(handle,dir, dx_get_block(at), 0,&retval)))
 +                      goto dxfail1;
 +
 +              BUFFER_TRACE(bh, "get_write_access");
 +              {
 +                      u32 newblock;
 +                      unsigned icount = dx_get_count(entries);
-+                      char *idata2;
 +                      int levels = frame - frames;
 +                      struct dx_entry *entries2;
++                      struct dx_node *node2;
 +                      struct buffer_head *bh2;
 +                      if (levels && dx_get_count(frames->entries) == dx_get_limit(frames->entries))
 +                              goto dxfull;
 +                      bh2 = ext3_append (handle, dir, &newblock, &retval);
 +                      if (!(bh2))
 +                              goto dxfail2;
-+                      idata2 = bh2->b_data;
-+                      entries2 = ((struct dx_node *) idata2)->entries;
-+                      ((struct dx_node *) idata2)->fake.rec_len = cpu_to_le16(blocksize);
-+                      /* fake.inode already 0 */
-+                      /* Seems that is not true. We still need to set inode = 0 -Chrisl*/
-+                      ((struct dx_node *) idata2)->fake.inode = 0;
++                      node2 = (struct dx_node *)(bh2->b_data);
++                      entries2 = node2->entries;
++                      node2->fake.rec_len = cpu_to_le16(blocksize);
++                      node2->fake.inode = 0;
 +                      BUFFER_TRACE(frame->bh, "get_write_access");
 +                      ext3_journal_get_write_access(handle, frame->bh);
 +                      if (levels)
 +                              dx_set_limit (entries2, dx_node_limit(dir));
 +
 +                              /* Which index block gets the new entry? */
-+                              if (at - entries > icount1) {
++                              if (at - entries >= icount1) {
 +                                      frame->at = at = at - entries - icount1 + entries2;
 +                                      frame->entries = entries = entries2;
 +                                      swap(frame->bh, bh2);
 +              dx_release (frames);
 +              goto fail1;
 +      }
-+      block = offset = 0;
-+      while (offset < dir->i_size) {
-+              bh = ext3_bread (handle, dir, block, 0, &retval);
++
++      blocks = dir->i_size >> sb->s_blocksize_bits;
++      for (block = 0, offset = 0; block < blocks; block++) {
++              bh = ext3_bread(handle, dir, block, 0, &retval);
 +              if(!bh)
-+                      return retval;  
-+              de = (struct ext3_dir_entry_2 *) bh->b_data;
-+              top = bh->b_data+blocksize-reclen;
++                      return retval;
++              de = (ext3_dirent *)bh->b_data;
++              top = bh->b_data + blocksize - reclen;
 +              while ((char *) de <= top) {
-+                      
-+                      if (!ext3_check_dir_entry ("ext3_add_entry", dir, de,
-+                                                 bh,offset)) {
++                      if (!ext3_check_dir_entry("ext3_add_entry", dir, de,
++                                                bh, offset)) {
 +                              brelse (bh);
-+                              return -ENOENT;
++                              return -EIO;
 +                      }
 +                      if (ext3_match (namelen, name, de)) {
                                brelse (bh);
 -                       */
 -                      dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 -                      dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
--                      ext3_mark_inode_dirty(handle, dir);
 -                      dir->i_version = ++event;
+-                      ext3_mark_inode_dirty(handle, dir);
 -                      BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
 -                      ext3_journal_dirty_metadata(handle, bh);
 +                      nlen = EXT3_DIR_REC_LEN(de->name_len);
 +                      rlen = le16_to_cpu(de->rec_len);
 +                      if ((de->inode? rlen - nlen: rlen) >= reclen)
 +                              goto add;
-+                      de = (struct ext3_dir_entry_2 *) ((char *) de + rlen);
++                      de = (ext3_dirent *)((char *)de + rlen);
 +                      offset += rlen;
 +              }
-+              if (ext3_dx && dir->i_size==blocksize && test_opt(sb, INDEX))
++              if (ext3_dx && blocks == 1 && test_opt(sb, INDEX))
 +                      goto dx_make_index;
 +              brelse(bh);
 +      }
 +      bh = ext3_append(handle, dir, &block, &retval);
 +      if (!bh)
 +              return retval;
-+      de = (struct ext3_dir_entry_2 *) bh->b_data;
++      de = (ext3_dirent *) bh->b_data;
 +      de->inode = 0;
 +      de->rec_len = cpu_to_le16(rlen = blocksize);
 +      nlen = 0;
 +      ext3_journal_get_write_access(handle, bh);
 +      /* By now the buffer is marked for journaling */
 +      if (de->inode) {
-+              de1 = (struct ext3_dir_entry_2 *) ((char *) de + nlen);
++              ext3_dirent *de1 = (ext3_dirent *)((char *)de + nlen);
 +              de1->rec_len = cpu_to_le16(rlen - nlen);
 +              de->rec_len = cpu_to_le16(nlen);
 +              de = de1;
 +       * and/or different from the directory change time.
 +       */
 +      dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-+      /* EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL; */
-+      ext3_mark_inode_dirty(handle, dir);
++      ext3_update_dx_flag(dir);
 +      dir->i_version = ++event;
++      ext3_mark_inode_dirty(handle, dir);
 +      BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
 +      ext3_journal_dirty_metadata(handle, bh);
 +      brelse(bh);
 +              struct dx_root *root;
 +              struct dx_frame frames[2], *frame;
 +              struct dx_entry *entries;
-+              struct ext3_dir_entry_2 *de2;
++              ext3_dirent *de2;
 +              char *data1;
 +              unsigned len;
 +              u32 hash;
 +              ext3_journal_get_write_access(handle, bh);
 +              root = (struct dx_root *) bh->b_data;
 +              
-+              ext3_add_compat_feature (sb, EXT3_FEATURE_COMPAT_DIR_INDEX);
 +              EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
 +              bh2 = ext3_append (handle, dir, &block, &retval);
 +              if (!(bh2))
 +                      de = de2;
 +              de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
 +              /* Initialize the root; the dot dirents already exist */
-+              de = (ext3_dirent *) (&root->fake2);
++              de = (ext3_dirent *) (&root->dotdot);
 +              de->rec_len = cpu_to_le16(blocksize - EXT3_DIR_REC_LEN(2));
 +              memset (&root->info, 0, sizeof(root->info));
 +              root->info.info_length = sizeof(root->info);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
  
+@@ -550,7 +1320,7 @@
+       if (err)
+               goto out_no_entry;
+       dir->i_nlink++;
+-      dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
++      ext3_update_dx_flag(dir);
+       ext3_mark_inode_dirty(handle, dir);
+       d_instantiate(dentry, inode);
+ out_stop:
 @@ -832,7 +1596,7 @@
        ext3_mark_inode_dirty(handle, inode);
        dir->i_nlink--;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 -      dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
-+      //      EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
++      ext3_update_dx_flag(dir);
        ext3_mark_inode_dirty(handle, dir);
  
  end_rmdir:
                goto end_unlink;
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 -      dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
-+      //      EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL;
++      ext3_update_dx_flag(dir);
        ext3_mark_inode_dirty(handle, dir);
        inode->i_nlink--;
        if (!inode->i_nlink)
        }
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
 -      old_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
-+      // EXT3_I(old_dir)->i_flags &= ~EXT3_INDEX_FL;
++      ext3_update_dx_flag(old_dir);
        if (dir_bh) {
                BUFFER_TRACE(dir_bh, "get_write_access");
                ext3_journal_get_write_access(handle, dir_bh);
                } else {
                        new_dir->i_nlink++;
 -                      new_dir->u.ext3_i.i_flags &= ~EXT3_INDEX_FL;
-+      //              EXT3_I(new_dir)->i_flags &= ~EXT3_INDEX_FL;
++                      ext3_update_dx_flag(new_dir);
                        ext3_mark_inode_dirty(handle, new_dir);
                }
        }