string: factorize skip_spaces and export it to be generally available
[safe/jmp/linux-2.6] / fs / ext3 / namei.c
index c1fa190..aad6400 100644 (file)
@@ -57,10 +57,15 @@ static struct buffer_head *ext3_append(handle_t *handle,
 
        *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
 
-       if ((bh = ext3_bread(handle, inode, *block, 1, err))) {
+       bh = ext3_bread(handle, inode, *block, 1, err);
+       if (bh) {
                inode->i_size += inode->i_sb->s_blocksize;
                EXT3_I(inode)->i_disksize = inode->i_size;
-               ext3_journal_get_write_access(handle,bh);
+               *err = ext3_journal_get_write_access(handle, bh);
+               if (*err) {
+                       brelse(bh);
+                       bh = NULL;
+               }
        }
        return bh;
 }
@@ -69,10 +74,6 @@ static struct buffer_head *ext3_append(handle_t *handle,
 #define assert(test) J_ASSERT(test)
 #endif
 
-#ifndef swap
-#define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0)
-#endif
-
 #ifdef DX_DEBUG
 #define dxtrace(command) command
 #else
@@ -144,7 +145,6 @@ struct dx_map_entry
        u16 size;
 };
 
-#ifdef CONFIG_EXT3_INDEX
 static inline unsigned dx_get_block (struct dx_entry *entry);
 static void dx_set_block (struct dx_entry *entry, unsigned value);
 static inline unsigned dx_get_hash (struct dx_entry *entry);
@@ -155,29 +155,40 @@ static void dx_set_count (struct dx_entry *entries, unsigned value);
 static void dx_set_limit (struct dx_entry *entries, unsigned value);
 static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
 static unsigned dx_node_limit (struct inode *dir);
-static struct dx_frame *dx_probe(struct dentry *dentry,
+static struct dx_frame *dx_probe(struct qstr *entry,
                                 struct inode *dir,
                                 struct dx_hash_info *hinfo,
                                 struct dx_frame *frame,
                                 int *err);
 static void dx_release (struct dx_frame *frames);
-static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
+static int dx_make_map(struct ext3_dir_entry_2 *de, unsigned blocksize,
                        struct dx_hash_info *hinfo, struct dx_map_entry map[]);
 static void dx_sort_map(struct dx_map_entry *map, unsigned count);
 static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to,
                struct dx_map_entry *offsets, int count);
-static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size);
+static struct ext3_dir_entry_2 *dx_pack_dirents(char *base, unsigned blocksize);
 static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
 static int ext3_htree_next_block(struct inode *dir, __u32 hash,
                                 struct dx_frame *frame,
                                 struct dx_frame *frames,
                                 __u32 *start_hash);
-static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
-                      struct ext3_dir_entry_2 **res_dir, int *err);
+static struct buffer_head * ext3_dx_find_entry(struct inode *dir,
+                       struct qstr *entry, struct ext3_dir_entry_2 **res_dir,
+                       int *err);
 static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
                             struct inode *inode);
 
 /*
+ * p is at least 6 bytes before the end of page
+ */
+static inline struct ext3_dir_entry_2 *
+ext3_next_entry(struct ext3_dir_entry_2 *p)
+{
+       return (struct ext3_dir_entry_2 *)((char *)p +
+               ext3_rec_len_from_disk(p->rec_len));
+}
+
+/*
  * Future: use high four bits of block for coalesce-on-delete flags
  * Mask them off for now.
  */
@@ -226,13 +237,13 @@ static inline unsigned dx_root_limit (struct inode *dir, unsigned 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);
+       return entry_space / sizeof(struct dx_entry);
 }
 
 static inline unsigned dx_node_limit (struct inode *dir)
 {
        unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0);
-       return 0? 22: entry_space / sizeof(struct dx_entry);
+       return entry_space / sizeof(struct dx_entry);
 }
 
 /*
@@ -281,7 +292,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_ent
                        space += EXT3_DIR_REC_LEN(de->name_len);
                        names++;
                }
-               de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+               de = ext3_next_entry(de);
        }
        printk("(%i)\n", names);
        return (struct stats) { names, space, 1 };
@@ -328,7 +339,7 @@ struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
  * back to userspace.
  */
 static struct dx_frame *
-dx_probe(struct dentry *dentry, struct inode *dir,
+dx_probe(struct qstr *entry, struct inode *dir,
         struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
 {
        unsigned count, indirect;
@@ -339,15 +350,13 @@ dx_probe(struct dentry *dentry, struct inode *dir,
        u32 hash;
 
        frame->bh = NULL;
-       if (dentry)
-               dir = dentry->d_parent->d_inode;
        if (!(bh = ext3_bread (NULL,dir, 0, 0, err)))
                goto fail;
        root = (struct dx_root *) bh->b_data;
        if (root->info.hash_version != DX_HASH_TEA &&
            root->info.hash_version != DX_HASH_HALF_MD4 &&
            root->info.hash_version != DX_HASH_LEGACY) {
-               ext3_warning(dir->i_sb, __FUNCTION__,
+               ext3_warning(dir->i_sb, __func__,
                             "Unrecognised inode hash code %d",
                             root->info.hash_version);
                brelse(bh);
@@ -355,13 +364,15 @@ dx_probe(struct dentry *dentry, struct inode *dir,
                goto fail;
        }
        hinfo->hash_version = root->info.hash_version;
+       if (hinfo->hash_version <= DX_HASH_TEA)
+               hinfo->hash_version += EXT3_SB(dir->i_sb)->s_hash_unsigned;
        hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed;
-       if (dentry)
-               ext3fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
+       if (entry)
+               ext3fs_dirhash(entry->name, entry->len, hinfo);
        hash = hinfo->hash;
 
        if (root->info.unused_flags & 1) {
-               ext3_warning(dir->i_sb, __FUNCTION__,
+               ext3_warning(dir->i_sb, __func__,
                             "Unimplemented inode hash flags: %#06x",
                             root->info.unused_flags);
                brelse(bh);
@@ -370,7 +381,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
        }
 
        if ((indirect = root->info.indirect_levels) > 1) {
-               ext3_warning(dir->i_sb, __FUNCTION__,
+               ext3_warning(dir->i_sb, __func__,
                             "Unimplemented inode hash depth: %#06x",
                             root->info.indirect_levels);
                brelse(bh);
@@ -383,7 +394,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
 
        if (dx_get_limit(entries) != dx_root_limit(dir,
                                                   root->info.info_length)) {
-               ext3_warning(dir->i_sb, __FUNCTION__,
+               ext3_warning(dir->i_sb, __func__,
                             "dx entry: limit != root limit");
                brelse(bh);
                *err = ERR_BAD_DX_DIR;
@@ -395,7 +406,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
        {
                count = dx_get_count(entries);
                if (!count || count > dx_get_limit(entries)) {
-                       ext3_warning(dir->i_sb, __FUNCTION__,
+                       ext3_warning(dir->i_sb, __func__,
                                     "dx entry: no count or count > limit");
                        brelse(bh);
                        *err = ERR_BAD_DX_DIR;
@@ -440,7 +451,7 @@ dx_probe(struct dentry *dentry, struct inode *dir,
                        goto fail2;
                at = entries = ((struct dx_node *) bh->b_data)->entries;
                if (dx_get_limit(entries) != dx_node_limit (dir)) {
-                       ext3_warning(dir->i_sb, __FUNCTION__,
+                       ext3_warning(dir->i_sb, __func__,
                                     "dx entry: limit != node limit");
                        brelse(bh);
                        *err = ERR_BAD_DX_DIR;
@@ -456,7 +467,7 @@ fail2:
        }
 fail:
        if (*err == ERR_BAD_DX_DIR)
-               ext3_warning(dir->i_sb, __FUNCTION__,
+               ext3_warning(dir->i_sb, __func__,
                             "Corrupt dir inode %ld, running e2fsck is "
                             "recommended.", dir->i_ino);
        return NULL;
@@ -548,14 +559,6 @@ static int ext3_htree_next_block(struct inode *dir, __u32 hash,
 
 
 /*
- * p is at least 6 bytes before the end of page
- */
-static inline struct ext3_dir_entry_2 *ext3_next_entry(struct ext3_dir_entry_2 *p)
-{
-       return (struct ext3_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len));
-}
-
-/*
  * This function fills a red-black tree with information from a
  * directory block.  It returns the number directory entries loaded
  * into the tree.  If there is an error it is returned in err.
@@ -631,6 +634,9 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
        dir = dir_file->f_path.dentry->d_inode;
        if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) {
                hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
+               if (hinfo.hash_version <= DX_HASH_TEA)
+                       hinfo.hash_version +=
+                               EXT3_SB(dir->i_sb)->s_hash_unsigned;
                hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
                count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo,
                                               start_hash, start_minor_hash);
@@ -702,14 +708,14 @@ errout:
  * Create map of hash values, offsets, and sizes, stored at end of block.
  * Returns number of entries mapped.
  */
-static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
-                       struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
+static int dx_make_map(struct ext3_dir_entry_2 *de, unsigned blocksize,
+               struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
 {
        int count = 0;
        char *base = (char *) de;
        struct dx_hash_info h = *hinfo;
 
-       while ((char *) de < base + size)
+       while ((char *) de < base + blocksize)
        {
                if (de->name_len && de->inode) {
                        ext3fs_dirhash(de->name, de->name_len, &h);
@@ -721,7 +727,7 @@ static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
                        cond_resched();
                }
                /* XXX: do we need to check rec_len == 0 case? -Chris */
-               de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+               de = ext3_next_entry(de);
        }
        return count;
 }
@@ -768,8 +774,6 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
        dx_set_block(new, block);
        dx_set_count(entries, count + 1);
 }
-#endif
-
 
 static void ext3_update_dx_flag(struct inode *inode)
 {
@@ -799,15 +803,15 @@ static inline int ext3_match (int len, const char * const name,
  */
 static inline int search_dirblock(struct buffer_head * bh,
                                  struct inode *dir,
-                                 struct dentry *dentry,
+                                 struct qstr *child,
                                  unsigned long offset,
                                  struct ext3_dir_entry_2 ** res_dir)
 {
        struct ext3_dir_entry_2 * de;
        char * dlimit;
        int de_len;
-       const char *name = dentry->d_name.name;
-       int namelen = dentry->d_name.len;
+       const char *name = child->name;
+       int namelen = child->len;
 
        de = (struct ext3_dir_entry_2 *) bh->b_data;
        dlimit = bh->b_data + dir->i_sb->s_blocksize;
@@ -825,7 +829,7 @@ static inline int search_dirblock(struct buffer_head * bh,
                        return 1;
                }
                /* prevent looping on a bad block */
-               de_len = le16_to_cpu(de->rec_len);
+               de_len = ext3_rec_len_from_disk(de->rec_len);
                if (de_len <= 0)
                        return -1;
                offset += de_len;
@@ -846,8 +850,9 @@ static inline int search_dirblock(struct buffer_head * bh,
  * The returned buffer_head has ->b_count elevated.  The caller is expected
  * to brelse() it when appropriate.
  */
-static struct buffer_head * ext3_find_entry (struct dentry *dentry,
-                                       struct ext3_dir_entry_2 ** res_dir)
+static struct buffer_head *ext3_find_entry(struct inode *dir,
+                                       struct qstr *entry,
+                                       struct ext3_dir_entry_2 **res_dir)
 {
        struct super_block * sb;
        struct buffer_head * bh_use[NAMEI_RA_SIZE];
@@ -859,21 +864,15 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
                                   buffer */
        int num = 0;
        int nblocks, i, err;
-       struct inode *dir = dentry->d_parent->d_inode;
        int namelen;
-       const u8 *name;
-       unsigned blocksize;
 
        *res_dir = NULL;
        sb = dir->i_sb;
-       blocksize = sb->s_blocksize;
-       namelen = dentry->d_name.len;
-       name = dentry->d_name.name;
+       namelen = entry->len;
        if (namelen > EXT3_NAME_LEN)
                return NULL;
-#ifdef CONFIG_EXT3_INDEX
        if (is_dx(dir)) {
-               bh = ext3_dx_find_entry(dentry, res_dir, &err);
+               bh = ext3_dx_find_entry(dir, entry, res_dir, &err);
                /*
                 * On success, or if the error was file not found,
                 * return.  Otherwise, fall back to doing a search the
@@ -883,7 +882,6 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
                        return bh;
                dxtrace(printk("ext3_find_entry: dx failed, falling back\n"));
        }
-#endif
        nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb);
        start = EXT3_I(dir)->i_dir_start_lookup;
        if (start >= nblocks)
@@ -920,12 +918,12 @@ restart:
                wait_on_buffer(bh);
                if (!buffer_uptodate(bh)) {
                        /* read error, skip block & hope for the best */
-                       ext3_error(sb, __FUNCTION__, "reading directory #%lu "
+                       ext3_error(sb, __func__, "reading directory #%lu "
                                   "offset %lu", dir->i_ino, block);
                        brelse(bh);
                        goto next;
                }
-               i = search_dirblock(bh, dir, dentry,
+               i = search_dirblock(bh, dir, entry,
                            block << EXT3_BLOCK_SIZE_BITS(sb), res_dir);
                if (i == 1) {
                        EXT3_I(dir)->i_dir_start_lookup = block;
@@ -959,9 +957,9 @@ cleanup_and_exit:
        return ret;
 }
 
-#ifdef CONFIG_EXT3_INDEX
-static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
-                      struct ext3_dir_entry_2 **res_dir, int *err)
+static struct buffer_head * ext3_dx_find_entry(struct inode *dir,
+                       struct qstr *entry, struct ext3_dir_entry_2 **res_dir,
+                       int *err)
 {
        struct super_block * sb;
        struct dx_hash_info     hinfo;
@@ -971,14 +969,13 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
        struct buffer_head *bh;
        unsigned long block;
        int retval;
-       int namelen = dentry->d_name.len;
-       const u8 *name = dentry->d_name.name;
-       struct inode *dir = dentry->d_parent->d_inode;
+       int namelen = entry->len;
+       const u8 *name = entry->name;
 
        sb = dir->i_sb;
        /* NFS may look up ".." - look at dx_root directory block */
-       if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
-               if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err)))
+       if (namelen > 2 || name[0] != '.'|| (namelen == 2 && name[1] != '.')) {
+               if (!(frame = dx_probe(entry, dir, &hinfo, frames, err)))
                        return NULL;
        } else {
                frame = frames;
@@ -994,26 +991,28 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
                de = (struct ext3_dir_entry_2 *) bh->b_data;
                top = (struct ext3_dir_entry_2 *) ((char *) de + sb->s_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",
-                                                 dir, de, bh,
-                                 (block<<EXT3_BLOCK_SIZE_BITS(sb))
-                                         +((char *)de - bh->b_data))) {
-                               brelse (bh);
+               for (; de < top; de = ext3_next_entry(de)) {
+                       int off = (block << EXT3_BLOCK_SIZE_BITS(sb))
+                                 + ((char *) de - bh->b_data);
+
+                       if (!ext3_check_dir_entry(__func__, dir, de, bh, off)) {
+                               brelse(bh);
                                *err = ERR_BAD_DX_DIR;
                                goto errout;
                        }
-                       *res_dir = de;
-                       dx_release (frames);
-                       return bh;
+
+                       if (ext3_match(namelen, name, de)) {
+                               *res_dir = de;
+                               dx_release(frames);
+                               return bh;
+                       }
                }
                brelse (bh);
                /* Check to see if we should continue to search */
                retval = ext3_htree_next_block(dir, hash, frame,
                                               frames, NULL);
                if (retval < 0) {
-                       ext3_warning(sb, __FUNCTION__,
+                       ext3_warning(sb, __func__,
                             "error reading index page in directory #%lu",
                             dir->i_ino);
                        *err = retval;
@@ -1027,7 +1026,6 @@ errout:
        dx_release (frames);
        return NULL;
 }
-#endif
 
 static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
 {
@@ -1038,7 +1036,7 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
        if (dentry->d_name.len > EXT3_NAME_LEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-       bh = ext3_find_entry(dentry, &de);
+       bh = ext3_find_entry(dir, &dentry->d_name, &de);
        inode = NULL;
        if (bh) {
                unsigned long ino = le32_to_cpu(de->inode);
@@ -1046,16 +1044,18 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
                if (!ext3_valid_inum(dir->i_sb, ino)) {
                        ext3_error(dir->i_sb, "ext3_lookup",
                                   "bad inode number: %lu", ino);
-                       inode = NULL;
-               } else
-                       inode = iget(dir->i_sb, ino);
-
-               if (!inode)
-                       return ERR_PTR(-EACCES);
-
-               if (is_bad_inode(inode)) {
-                       iput(inode);
-                       return ERR_PTR(-ENOENT);
+                       return ERR_PTR(-EIO);
+               }
+               inode = ext3_iget(dir->i_sb, ino);
+               if (unlikely(IS_ERR(inode))) {
+                       if (PTR_ERR(inode) == -ESTALE) {
+                               ext3_error(dir->i_sb, __func__,
+                                               "deleted inode referenced: %lu",
+                                               ino);
+                               return ERR_PTR(-EIO);
+                       } else {
+                               return ERR_CAST(inode);
+                       }
                }
        }
        return d_splice_alias(inode, dentry);
@@ -1065,18 +1065,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
 struct dentry *ext3_get_parent(struct dentry *child)
 {
        unsigned long ino;
-       struct dentry *parent;
-       struct inode *inode;
-       struct dentry dotdot;
+       struct qstr dotdot = {.name = "..", .len = 2};
        struct ext3_dir_entry_2 * de;
        struct buffer_head *bh;
 
-       dotdot.d_name.name = "..";
-       dotdot.d_name.len = 2;
-       dotdot.d_parent = child; /* confusing, isn't it! */
-
-       bh = ext3_find_entry(&dotdot, &de);
-       inode = NULL;
+       bh = ext3_find_entry(child->d_inode, &dotdot, &de);
        if (!bh)
                return ERR_PTR(-ENOENT);
        ino = le32_to_cpu(de->inode);
@@ -1085,24 +1078,10 @@ struct dentry *ext3_get_parent(struct dentry *child)
        if (!ext3_valid_inum(child->d_inode->i_sb, ino)) {
                ext3_error(child->d_inode->i_sb, "ext3_get_parent",
                           "bad inode number: %lu", ino);
-               inode = NULL;
-       } else
-               inode = iget(child->d_inode->i_sb, ino);
-
-       if (!inode)
-               return ERR_PTR(-EACCES);
-
-       if (is_bad_inode(inode)) {
-               iput(inode);
-               return ERR_PTR(-ENOENT);
+               return ERR_PTR(-EIO);
        }
 
-       parent = d_alloc_anon(inode);
-       if (!parent) {
-               iput(inode);
-               parent = ERR_PTR(-ENOMEM);
-       }
-       return parent;
+       return d_obtain_alias(ext3_iget(child->d_inode->i_sb, ino));
 }
 
 #define S_SHIFT 12
@@ -1123,7 +1102,6 @@ static inline void ext3_set_de_type(struct super_block *sb,
                de->file_type = ext3_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
 }
 
-#ifdef CONFIG_EXT3_INDEX
 /*
  * Move count entries from end of map between two memory locations.
  * Returns pointer to last entry moved.
@@ -1138,7 +1116,7 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
                rec_len = EXT3_DIR_REC_LEN(de->name_len);
                memcpy (to, de, rec_len);
                ((struct ext3_dir_entry_2 *) to)->rec_len =
-                               cpu_to_le16(rec_len);
+                               ext3_rec_len_to_disk(rec_len);
                de->inode = 0;
                map++;
                to += rec_len;
@@ -1150,20 +1128,20 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
  * Compact each dir entry in the range to the minimal rec_len.
  * Returns pointer to last entry in range.
  */
-static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
+static struct ext3_dir_entry_2 *dx_pack_dirents(char *base, unsigned blocksize)
 {
-       struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base;
+       struct ext3_dir_entry_2 *next, *to, *prev;
+       struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *)base;
        unsigned rec_len = 0;
 
        prev = to = de;
-       while ((char*)de < base + size) {
-               next = (struct ext3_dir_entry_2 *) ((char *) de +
-                                                   le16_to_cpu(de->rec_len));
+       while ((char *)de < base + blocksize) {
+               next = ext3_next_entry(de);
                if (de->inode && de->name_len) {
                        rec_len = EXT3_DIR_REC_LEN(de->name_len);
                        if (de > to)
                                memmove(to, de, rec_len);
-                       to->rec_len = cpu_to_le16(rec_len);
+                       to->rec_len = ext3_rec_len_to_disk(rec_len);
                        prev = to;
                        to = (struct ext3_dir_entry_2 *) (((char *) to) + rec_len);
                }
@@ -1188,9 +1166,9 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
        u32 hash2;
        struct dx_map_entry *map;
        char *data1 = (*bh)->b_data, *data2;
-       unsigned split, move, size, i;
+       unsigned split, move, size;
        struct ext3_dir_entry_2 *de = NULL, *de2;
-       int     err = 0;
+       int     err = 0, i;
 
        bh2 = ext3_append (handle, dir, &newblock, &err);
        if (!(bh2)) {
@@ -1237,8 +1215,8 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
        /* Fancy dance to stay within two buffers */
        de2 = dx_move_dirents(data1, data2, map + split, count - split);
        de = dx_pack_dirents(data1,blocksize);
-       de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
-       de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2);
+       de->rec_len = ext3_rec_len_to_disk(data1 + blocksize - (char *) de);
+       de2->rec_len = ext3_rec_len_to_disk(data2 + blocksize - (char *) de2);
        dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1));
        dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1));
 
@@ -1268,7 +1246,6 @@ errout:
        *error = err;
        return NULL;
 }
-#endif
 
 
 /*
@@ -1309,7 +1286,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
                                return -EEXIST;
                        }
                        nlen = EXT3_DIR_REC_LEN(de->name_len);
-                       rlen = le16_to_cpu(de->rec_len);
+                       rlen = ext3_rec_len_from_disk(de->rec_len);
                        if ((de->inode? rlen - nlen: rlen) >= reclen)
                                break;
                        de = (struct ext3_dir_entry_2 *)((char *)de + rlen);
@@ -1328,11 +1305,11 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
 
        /* By now the buffer is marked for journaling */
        nlen = EXT3_DIR_REC_LEN(de->name_len);
-       rlen = le16_to_cpu(de->rec_len);
+       rlen = ext3_rec_len_from_disk(de->rec_len);
        if (de->inode) {
                struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen);
-               de1->rec_len = cpu_to_le16(rlen - nlen);
-               de->rec_len = cpu_to_le16(nlen);
+               de1->rec_len = ext3_rec_len_to_disk(rlen - nlen);
+               de->rec_len = ext3_rec_len_to_disk(nlen);
                de = de1;
        }
        de->file_type = EXT3_FT_UNKNOWN;
@@ -1366,7 +1343,6 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
        return 0;
 }
 
-#ifdef CONFIG_EXT3_INDEX
 /*
  * This converts a one block unindexed directory to a 3 block indexed
  * directory, and adds the dentry to the indexed directory.
@@ -1391,7 +1367,7 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        struct fake_dirent *fde;
 
        blocksize =  dir->i_sb->s_blocksize;
-       dxtrace(printk("Creating index\n"));
+       dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino));
        retval = ext3_journal_get_write_access(handle, bh);
        if (retval) {
                ext3_std_error(dir->i_sb, retval);
@@ -1400,6 +1376,19 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        }
        root = (struct dx_root *) bh->b_data;
 
+       /* The 0th block becomes the root, move the dirents out */
+       fde = &root->dotdot;
+       de = (struct ext3_dir_entry_2 *)((char *)fde +
+                       ext3_rec_len_from_disk(fde->rec_len));
+       if ((char *) de >= (((char *) root) + blocksize)) {
+               ext3_error(dir->i_sb, __func__,
+                          "invalid rec_len for '..' in inode %lu",
+                          dir->i_ino);
+               brelse(bh);
+               return -EIO;
+       }
+       len = ((char *) root) + blocksize - (char *) de;
+
        bh2 = ext3_append (handle, dir, &block, &retval);
        if (!(bh2)) {
                brelse(bh);
@@ -1408,19 +1397,15 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
        EXT3_I(dir)->i_flags |= EXT3_INDEX_FL;
        data1 = bh2->b_data;
 
-       /* The 0th block becomes the root, move the dirents out */
-       fde = &root->dotdot;
-       de = (struct ext3_dir_entry_2 *)((char *)fde + le16_to_cpu(fde->rec_len));
-       len = ((char *) root) + blocksize - (char *) de;
        memcpy (data1, de, len);
        de = (struct ext3_dir_entry_2 *) data1;
        top = data1 + len;
-       while ((char *)(de2=(void*)de+le16_to_cpu(de->rec_len)) < top)
+       while ((char *)(de2 = ext3_next_entry(de)) < top)
                de = de2;
-       de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
+       de->rec_len = ext3_rec_len_to_disk(data1 + blocksize - (char *) de);
        /* Initialize the root; the dot dirents already exist */
        de = (struct ext3_dir_entry_2 *) (&root->dotdot);
-       de->rec_len = cpu_to_le16(blocksize - EXT3_DIR_REC_LEN(2));
+       de->rec_len = ext3_rec_len_to_disk(blocksize - EXT3_DIR_REC_LEN(2));
        memset (&root->info, 0, sizeof(root->info));
        root->info.info_length = sizeof(root->info);
        root->info.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
@@ -1431,6 +1416,8 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
 
        /* Initialize as for dx_probe */
        hinfo.hash_version = root->info.hash_version;
+       if (hinfo.hash_version <= DX_HASH_TEA)
+               hinfo.hash_version += EXT3_SB(dir->i_sb)->s_hash_unsigned;
        hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
        ext3fs_dirhash(name, namelen, &hinfo);
        frame = frames;
@@ -1445,7 +1432,6 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
 
        return add_dirent_to_buf(handle, dentry, inode, de, bh);
 }
-#endif
 
 /*
  *     ext3_add_entry()
@@ -1466,9 +1452,7 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
        struct ext3_dir_entry_2 *de;
        struct super_block * sb;
        int     retval;
-#ifdef CONFIG_EXT3_INDEX
        int     dx_fallback=0;
-#endif
        unsigned blocksize;
        u32 block, blocks;
 
@@ -1476,7 +1460,6 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
        blocksize = sb->s_blocksize;
        if (!dentry->d_name.len)
                return -EINVAL;
-#ifdef CONFIG_EXT3_INDEX
        if (is_dx(dir)) {
                retval = ext3_dx_add_entry(handle, dentry, inode);
                if (!retval || (retval != ERR_BAD_DX_DIR))
@@ -1485,7 +1468,6 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
                dx_fallback++;
                ext3_mark_inode_dirty(handle, dir);
        }
-#endif
        blocks = dir->i_size >> sb->s_blocksize_bits;
        for (block = 0, offset = 0; block < blocks; block++) {
                bh = ext3_bread(handle, dir, block, 0, &retval);
@@ -1495,11 +1477,9 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
                if (retval != -ENOSPC)
                        return retval;
 
-#ifdef CONFIG_EXT3_INDEX
                if (blocks == 1 && !dx_fallback &&
                    EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX))
                        return make_indexed_dir(handle, dentry, inode, bh);
-#endif
                brelse(bh);
        }
        bh = ext3_append(handle, dir, &block, &retval);
@@ -1507,11 +1487,10 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
                return retval;
        de = (struct ext3_dir_entry_2 *) bh->b_data;
        de->inode = 0;
-       de->rec_len = cpu_to_le16(blocksize);
+       de->rec_len = ext3_rec_len_to_disk(blocksize);
        return add_dirent_to_buf(handle, dentry, inode, de, bh);
 }
 
-#ifdef CONFIG_EXT3_INDEX
 /*
  * Returns 0 for success, or a negative error value
  */
@@ -1527,7 +1506,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
        struct ext3_dir_entry_2 *de;
        int err;
 
-       frame = dx_probe(dentry, NULL, &hinfo, frames, &err);
+       frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err);
        if (!frame)
                return err;
        entries = frame->entries;
@@ -1561,7 +1540,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
 
                if (levels && (dx_get_count(frames->entries) ==
                               dx_get_limit(frames->entries))) {
-                       ext3_warning(sb, __FUNCTION__,
+                       ext3_warning(sb, __func__,
                                     "Directory index full!");
                        err = -ENOSPC;
                        goto cleanup;
@@ -1571,7 +1550,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry,
                        goto cleanup;
                node2 = (struct dx_node *)(bh2->b_data);
                entries2 = node2->entries;
-               node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
+               node2->fake.rec_len = ext3_rec_len_to_disk(sb->s_blocksize);
                node2->fake.inode = 0;
                BUFFER_TRACE(frame->bh, "get_write_access");
                err = ext3_journal_get_write_access(handle, frame->bh);
@@ -1646,7 +1625,6 @@ cleanup:
        dx_release(frames);
        return err;
 }
-#endif
 
 /*
  * ext3_delete_entry deletes a directory entry by merging it with the
@@ -1670,9 +1648,9 @@ static int ext3_delete_entry (handle_t *handle,
                        BUFFER_TRACE(bh, "get_write_access");
                        ext3_journal_get_write_access(handle, bh);
                        if (pde)
-                               pde->rec_len =
-                                       cpu_to_le16(le16_to_cpu(pde->rec_len) +
-                                                   le16_to_cpu(de->rec_len));
+                               pde->rec_len = ext3_rec_len_to_disk(
+                                       ext3_rec_len_from_disk(pde->rec_len) +
+                                       ext3_rec_len_from_disk(de->rec_len));
                        else
                                de->inode = 0;
                        dir->i_version++;
@@ -1680,10 +1658,9 @@ static int ext3_delete_entry (handle_t *handle,
                        ext3_journal_dirty_metadata(handle, bh);
                        return 0;
                }
-               i += le16_to_cpu(de->rec_len);
+               i += ext3_rec_len_from_disk(de->rec_len);
                pde = de;
-               de = (struct ext3_dir_entry_2 *)
-                       ((char *) de + le16_to_cpu(de->rec_len));
+               de = ext3_next_entry(de);
        }
        return -ENOENT;
 }
@@ -1695,9 +1672,11 @@ static int ext3_add_nondir(handle_t *handle,
        if (!err) {
                ext3_mark_inode_dirty(handle, inode);
                d_instantiate(dentry, inode);
+               unlock_new_inode(inode);
                return 0;
        }
        drop_nlink(inode);
+       unlock_new_inode(inode);
        iput(inode);
        return err;
 }
@@ -1808,6 +1787,7 @@ retry:
        dir_block = ext3_bread (handle, inode, 0, 1, &err);
        if (!dir_block) {
                drop_nlink(inode); /* is this nlink == 0? */
+               unlock_new_inode(inode);
                ext3_mark_inode_dirty(handle, inode);
                iput (inode);
                goto out_stop;
@@ -1817,13 +1797,13 @@ retry:
        de = (struct ext3_dir_entry_2 *) dir_block->b_data;
        de->inode = cpu_to_le32(inode->i_ino);
        de->name_len = 1;
-       de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(de->name_len));
+       de->rec_len = ext3_rec_len_to_disk(EXT3_DIR_REC_LEN(de->name_len));
        strcpy (de->name, ".");
        ext3_set_de_type(dir->i_sb, de, S_IFDIR);
-       de = (struct ext3_dir_entry_2 *)
-                       ((char *) de + le16_to_cpu(de->rec_len));
+       de = ext3_next_entry(de);
        de->inode = cpu_to_le32(dir->i_ino);
-       de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT3_DIR_REC_LEN(1));
+       de->rec_len = ext3_rec_len_to_disk(inode->i_sb->s_blocksize -
+                                       EXT3_DIR_REC_LEN(1));
        de->name_len = 2;
        strcpy (de->name, "..");
        ext3_set_de_type(dir->i_sb, de, S_IFDIR);
@@ -1835,6 +1815,7 @@ retry:
        err = ext3_add_entry (handle, dentry, inode);
        if (err) {
                inode->i_nlink = 0;
+               unlock_new_inode(inode);
                ext3_mark_inode_dirty(handle, inode);
                iput (inode);
                goto out_stop;
@@ -1843,6 +1824,7 @@ retry:
        ext3_update_dx_flag(dir);
        ext3_mark_inode_dirty(handle, dir);
        d_instantiate(dentry, inode);
+       unlock_new_inode(inode);
 out_stop:
        ext3_journal_stop(handle);
        if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
@@ -1865,18 +1847,17 @@ static int empty_dir (struct inode * inode)
        if (inode->i_size < EXT3_DIR_REC_LEN(1) + EXT3_DIR_REC_LEN(2) ||
            !(bh = ext3_bread (NULL, inode, 0, 0, &err))) {
                if (err)
-                       ext3_error(inode->i_sb, __FUNCTION__,
+                       ext3_error(inode->i_sb, __func__,
                                   "error %d reading directory #%lu offset 0",
                                   err, inode->i_ino);
                else
-                       ext3_warning(inode->i_sb, __FUNCTION__,
+                       ext3_warning(inode->i_sb, __func__,
                                     "bad directory (dir #%lu) - no data block",
                                     inode->i_ino);
                return 1;
        }
        de = (struct ext3_dir_entry_2 *) bh->b_data;
-       de1 = (struct ext3_dir_entry_2 *)
-                       ((char *) de + le16_to_cpu(de->rec_len));
+       de1 = ext3_next_entry(de);
        if (le32_to_cpu(de->inode) != inode->i_ino ||
                        !le32_to_cpu(de1->inode) ||
                        strcmp (".", de->name) ||
@@ -1887,9 +1868,9 @@ static int empty_dir (struct inode * inode)
                brelse (bh);
                return 1;
        }
-       offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
-       de = (struct ext3_dir_entry_2 *)
-                       ((char *) de1 + le16_to_cpu(de1->rec_len));
+       offset = ext3_rec_len_from_disk(de->rec_len) +
+                       ext3_rec_len_from_disk(de1->rec_len);
+       de = ext3_next_entry(de1);
        while (offset < inode->i_size ) {
                if (!bh ||
                        (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
@@ -1899,7 +1880,7 @@ static int empty_dir (struct inode * inode)
                                offset >> EXT3_BLOCK_SIZE_BITS(sb), 0, &err);
                        if (!bh) {
                                if (err)
-                                       ext3_error(sb, __FUNCTION__,
+                                       ext3_error(sb, __func__,
                                                   "error %d reading directory"
                                                   " #%lu offset %lu",
                                                   err, inode->i_ino, offset);
@@ -1918,9 +1899,8 @@ static int empty_dir (struct inode * inode)
                        brelse (bh);
                        return 0;
                }
-               offset += le16_to_cpu(de->rec_len);
-               de = (struct ext3_dir_entry_2 *)
-                               ((char *) de + le16_to_cpu(de->rec_len));
+               offset += ext3_rec_len_from_disk(de->rec_len);
+               de = ext3_next_entry(de);
        }
        brelse (bh);
        return 1;
@@ -2078,13 +2058,13 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
 
        /* Initialize quotas before so that eventual writes go in
         * separate transaction */
-       DQUOT_INIT(dentry->d_inode);
+       vfs_dq_init(dentry->d_inode);
        handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
        retval = -ENOENT;
-       bh = ext3_find_entry (dentry, &de);
+       bh = ext3_find_entry(dir, &dentry->d_name, &de);
        if (!bh)
                goto end_rmdir;
 
@@ -2137,7 +2117,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
 
        /* Initialize quotas before so that eventual writes go
         * in separate transaction */
-       DQUOT_INIT(dentry->d_inode);
+       vfs_dq_init(dentry->d_inode);
        handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
@@ -2146,7 +2126,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
                handle->h_sync = 1;
 
        retval = -ENOENT;
-       bh = ext3_find_entry (dentry, &de);
+       bh = ext3_find_entry(dir, &dentry->d_name, &de);
        if (!bh)
                goto end_unlink;
 
@@ -2215,10 +2195,10 @@ retry:
                 * We have a transaction open.  All is sweetness.  It also sets
                 * i_size in generic_commit_write().
                 */
-               err = __page_symlink(inode, symname, l,
-                               mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
+               err = __page_symlink(inode, symname, l, 1);
                if (err) {
                        drop_nlink(inode);
+                       unlock_new_inode(inode);
                        ext3_mark_inode_dirty(handle, inode);
                        iput (inode);
                        goto out_stop;
@@ -2266,7 +2246,14 @@ retry:
        inc_nlink(inode);
        atomic_inc(&inode->i_count);
 
-       err = ext3_add_nondir(handle, dentry, inode);
+       err = ext3_add_entry(handle, dentry, inode);
+       if (!err) {
+               ext3_mark_inode_dirty(handle, inode);
+               d_instantiate(dentry, inode);
+       } else {
+               drop_nlink(inode);
+               iput(inode);
+       }
        ext3_journal_stop(handle);
        if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
                goto retry;
@@ -2274,8 +2261,7 @@ retry:
 }
 
 #define PARENT_INO(buffer) \
-       ((struct ext3_dir_entry_2 *) ((char *) buffer + \
-       le16_to_cpu(((struct ext3_dir_entry_2 *) buffer)->rec_len)))->inode
+       (ext3_next_entry((struct ext3_dir_entry_2 *)(buffer))->inode)
 
 /*
  * Anybody can rename anything with this: the permission checks are left to the
@@ -2288,14 +2274,14 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
        struct inode * old_inode, * new_inode;
        struct buffer_head * old_bh, * new_bh, * dir_bh;
        struct ext3_dir_entry_2 * old_de, * new_de;
-       int retval;
+       int retval, flush_file = 0;
 
        old_bh = new_bh = dir_bh = NULL;
 
        /* Initialize quotas before so that eventual writes go
         * in separate transaction */
        if (new_dentry->d_inode)
-               DQUOT_INIT(new_dentry->d_inode);
+               vfs_dq_init(new_dentry->d_inode);
        handle = ext3_journal_start(old_dir, 2 *
                                        EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) +
                                        EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
@@ -2305,7 +2291,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
        if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
                handle->h_sync = 1;
 
-       old_bh = ext3_find_entry (old_dentry, &old_de);
+       old_bh = ext3_find_entry(old_dir, &old_dentry->d_name, &old_de);
        /*
         *  Check for inode number is _not_ due to possible IO errors.
         *  We might rmdir the source, keep it as pwd of some process
@@ -2318,7 +2304,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
                goto end_rename;
 
        new_inode = new_dentry->d_inode;
-       new_bh = ext3_find_entry (new_dentry, &new_de);
+       new_bh = ext3_find_entry(new_dir, &new_dentry->d_name, &new_de);
        if (new_bh) {
                if (!new_inode) {
                        brelse (new_bh);
@@ -2354,6 +2340,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
                                              EXT3_FEATURE_INCOMPAT_FILETYPE))
                        new_de->file_type = old_de->file_type;
                new_dir->i_version++;
+               new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME_SEC;
+               ext3_mark_inode_dirty(handle, new_dir);
                BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata");
                ext3_journal_dirty_metadata(handle, new_bh);
                brelse(new_bh);
@@ -2382,7 +2370,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
                struct buffer_head *old_bh2;
                struct ext3_dir_entry_2 *old_de2;
 
-               old_bh2 = ext3_find_entry(old_dentry, &old_de2);
+               old_bh2 = ext3_find_entry(old_dir, &old_dentry->d_name,
+                                         &old_de2);
                if (old_bh2) {
                        retval = ext3_delete_entry(handle, old_dir,
                                                   old_de2, old_bh2);
@@ -2421,6 +2410,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
                ext3_mark_inode_dirty(handle, new_inode);
                if (!new_inode->i_nlink)
                        ext3_orphan_add(handle, new_inode);
+               if (ext3_should_writeback_data(new_inode))
+                       flush_file = 1;
        }
        retval = 0;
 
@@ -2429,6 +2420,8 @@ end_rename:
        brelse (old_bh);
        brelse (new_bh);
        ext3_journal_stop(handle);
+       if (retval == 0 && flush_file)
+               filemap_flush(old_inode->i_mapping);
        return retval;
 }
 
@@ -2452,7 +2445,7 @@ const struct inode_operations ext3_dir_inode_operations = {
        .listxattr      = ext3_listxattr,
        .removexattr    = generic_removexattr,
 #endif
-       .permission     = ext3_permission,
+       .check_acl      = ext3_check_acl,
 };
 
 const struct inode_operations ext3_special_inode_operations = {
@@ -2463,5 +2456,5 @@ const struct inode_operations ext3_special_inode_operations = {
        .listxattr      = ext3_listxattr,
        .removexattr    = generic_removexattr,
 #endif
-       .permission     = ext3_permission,
+       .check_acl      = ext3_check_acl,
 };