[JFFS2] Quiet lockdep false positive.
[safe/jmp/linux-2.6] / fs / ext3 / namei.c
index 1586807..dec3e0d 100644 (file)
@@ -140,10 +140,10 @@ struct dx_frame
 struct dx_map_entry
 {
        u32 hash;
-       u32 offs;
+       u16 offs;
+       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);
@@ -177,6 +177,16 @@ 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.
  */
@@ -280,7 +290,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 };
@@ -379,13 +389,28 @@ dx_probe(struct dentry *dentry, struct inode *dir,
 
        entries = (struct dx_entry *) (((char *)&root->info) +
                                       root->info.info_length);
-       assert(dx_get_limit(entries) == dx_root_limit(dir,
-                                                     root->info.info_length));
+
+       if (dx_get_limit(entries) != dx_root_limit(dir,
+                                                  root->info.info_length)) {
+               ext3_warning(dir->i_sb, __FUNCTION__,
+                            "dx entry: limit != root limit");
+               brelse(bh);
+               *err = ERR_BAD_DX_DIR;
+               goto fail;
+       }
+
        dxtrace (printk("Look up %x", hash));
        while (1)
        {
                count = dx_get_count(entries);
-               assert (count && count <= dx_get_limit(entries));
+               if (!count || count > dx_get_limit(entries)) {
+                       ext3_warning(dir->i_sb, __FUNCTION__,
+                                    "dx entry: no count or count > limit");
+                       brelse(bh);
+                       *err = ERR_BAD_DX_DIR;
+                       goto fail2;
+               }
+
                p = entries + 1;
                q = entries + count - 1;
                while (p <= q)
@@ -423,8 +448,15 @@ dx_probe(struct dentry *dentry, struct inode *dir,
                if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
                        goto fail2;
                at = entries = ((struct dx_node *) bh->b_data)->entries;
-               assert (dx_get_limit(entries) == dx_node_limit (dir));
+               if (dx_get_limit(entries) != dx_node_limit (dir)) {
+                       ext3_warning(dir->i_sb, __FUNCTION__,
+                                    "dx entry: limit != node limit");
+                       brelse(bh);
+                       *err = ERR_BAD_DX_DIR;
+                       goto fail2;
+               }
                frame++;
+               frame->bh = NULL;
        }
 fail2:
        while (frame >= frame_in) {
@@ -432,6 +464,10 @@ fail2:
                frame--;
        }
 fail:
+       if (*err == ERR_BAD_DX_DIR)
+               ext3_warning(dir->i_sb, __FUNCTION__,
+                            "Corrupt dir inode %ld, running e2fsck is "
+                            "recommended.", dir->i_ino);
        return NULL;
 }
 
@@ -521,14 +557,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.
@@ -671,6 +699,10 @@ errout:
  * Directory block splitting, compacting
  */
 
+/*
+ * 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)
 {
@@ -684,16 +716,18 @@ static int dx_make_map (struct ext3_dir_entry_2 *de, int size,
                        ext3fs_dirhash(de->name, de->name_len, &h);
                        map_tail--;
                        map_tail->hash = h.hash;
-                       map_tail->offs = (u32) ((char *) de - base);
+                       map_tail->offs = (u16) ((char *) de - base);
+                       map_tail->size = le16_to_cpu(de->rec_len);
                        count++;
                        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;
 }
 
+/* Sort map by hash value */
 static void dx_sort_map (struct dx_map_entry *map, unsigned count)
 {
         struct dx_map_entry *p, *q, *top = map + count - 1;
@@ -735,8 +769,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)
 {
@@ -792,7 +824,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;
@@ -828,17 +860,12 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry,
        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;
        if (namelen > EXT3_NAME_LEN)
                return NULL;
-#ifdef CONFIG_EXT3_INDEX
        if (is_dx(dir)) {
                bh = ext3_dx_find_entry(dentry, res_dir, &err);
                /*
@@ -850,7 +877,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)
@@ -926,7 +952,6 @@ 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)
 {
@@ -994,7 +1019,6 @@ errout:
        dx_release (frames);
        return NULL;
 }
-#endif
 
 static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
 {
@@ -1013,17 +1037,11 @@ 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 (IS_ERR(inode))
+                       return ERR_CAST(inode);
        }
        return d_splice_alias(inode, dentry);
 }
@@ -1052,18 +1070,13 @@ 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);
        }
 
+       inode = ext3_iget(child->d_inode->i_sb, ino);
+       if (IS_ERR(inode))
+               return ERR_CAST(inode);
+
        parent = d_alloc_anon(inode);
        if (!parent) {
                iput(inode);
@@ -1090,7 +1103,10 @@ 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.
+ */
 static struct ext3_dir_entry_2 *
 dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
 {
@@ -1101,7 +1117,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;
@@ -1109,6 +1125,10 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
        return (struct ext3_dir_entry_2 *) (to - rec_len);
 }
 
+/*
+ * 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)
 {
        struct ext3_dir_entry_2 *next, *to, *prev, *de = (struct ext3_dir_entry_2 *) base;
@@ -1116,13 +1136,12 @@ static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
 
        prev = to = de;
        while ((char*)de < base + size) {
-               next = (struct ext3_dir_entry_2 *) ((char *) de +
-                                                   le16_to_cpu(de->rec_len));
+               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);
                }
@@ -1131,6 +1150,11 @@ static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size)
        return prev;
 }
 
+/*
+ * Split a full leaf block to make room for a new dir entry.
+ * Allocate a new block, and move entries so that they are approx. equally full.
+ * Returns pointer to de in block into which the new entry will be inserted.
+ */
 static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                        struct buffer_head **bh,struct dx_frame *frame,
                        struct dx_hash_info *hinfo, int *error)
@@ -1142,7 +1166,7 @@ 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;
+       unsigned split, move, size, i;
        struct ext3_dir_entry_2 *de = NULL, *de2;
        int     err = 0;
 
@@ -1170,8 +1194,19 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
        count = dx_make_map ((struct ext3_dir_entry_2 *) data1,
                             blocksize, hinfo, map);
        map -= count;
-       split = count/2; // need to adjust to actual middle
        dx_sort_map (map, count);
+       /* Split the existing block in the middle, size-wise */
+       size = 0;
+       move = 0;
+       for (i = count-1; i >= 0; i--) {
+               /* is more than half of this entry in 2nd half of the block? */
+               if (size + map[i].size/2 > blocksize/2)
+                       break;
+               size += map[i].size;
+               move++;
+       }
+       /* map index at which we will split */
+       split = count - move;
        hash2 = map[split].hash;
        continued = hash2 == map[split - 1].hash;
        dxtrace(printk("Split block %i at %x, %i/%i\n",
@@ -1180,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));
 
@@ -1211,7 +1246,6 @@ errout:
        *error = err;
        return NULL;
 }
-#endif
 
 
 /*
@@ -1252,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);
@@ -1271,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;
@@ -1309,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.
@@ -1353,17 +1386,18 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
 
        /* 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));
+       de = (struct ext3_dir_entry_2 *)((char *)fde +
+                       ext3_rec_len_from_disk(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;
@@ -1388,7 +1422,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()
@@ -1409,9 +1442,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;
 
@@ -1419,7 +1450,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))
@@ -1428,7 +1458,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);
@@ -1438,11 +1467,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);
@@ -1450,11 +1477,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
  */
@@ -1514,7 +1540,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);
@@ -1589,7 +1615,6 @@ cleanup:
        dx_release(frames);
        return err;
 }
-#endif
 
 /*
  * ext3_delete_entry deletes a directory entry by merging it with the
@@ -1613,9 +1638,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++;
@@ -1623,10 +1648,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;
 }
@@ -1760,13 +1784,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);
@@ -1818,8 +1842,7 @@ static int empty_dir (struct inode * inode)
                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) ||
@@ -1830,9 +1853,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)) {
@@ -1861,9 +1884,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;
@@ -2217,8 +2239,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