Merge tag 'powerpc-5.9-3' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-2.6-microblaze.git] / fs / ext4 / namei.c
index 56738b5..153a9fb 100644 (file)
@@ -1396,8 +1396,8 @@ int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size,
                    ext4_match(dir, fname, de)) {
                        /* found a match - just to be sure, do
                         * a full check */
-                       if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data,
-                                                bh->b_size, offset))
+                       if (ext4_check_dir_entry(dir, NULL, de, bh, search_buf,
+                                                buf_size, offset))
                                return -1;
                        *res_dir = de;
                        return 1;
@@ -1858,7 +1858,7 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                             blocksize, hinfo, map);
        map -= count;
        dx_sort_map(map, count);
-       /* Split the existing block in the middle, size-wise */
+       /* Ensure that neither split block is over half full */
        size = 0;
        move = 0;
        for (i = count-1; i >= 0; i--) {
@@ -1868,8 +1868,18 @@ static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                size += map[i].size;
                move++;
        }
-       /* map index at which we will split */
-       split = count - move;
+       /*
+        * map index at which we will split
+        *
+        * If the sum of active entries didn't exceed half the block size, just
+        * split it in half by count; each resulting block will have at least
+        * half the space free.
+        */
+       if (i > 0)
+               split = count - move;
+       else
+               split = count/2;
+
        hash2 = map[split].hash;
        continued = hash2 == map[split - 1].hash;
        dxtrace(printk(KERN_INFO "Split block %lu at %x, %i/%i\n",
@@ -2455,8 +2465,7 @@ cleanup:
  * ext4_generic_delete_entry deletes a directory entry by merging it
  * with the previous entry
  */
-int ext4_generic_delete_entry(handle_t *handle,
-                             struct inode *dir,
+int ext4_generic_delete_entry(struct inode *dir,
                              struct ext4_dir_entry_2 *de_del,
                              struct buffer_head *bh,
                              void *entry_buf,
@@ -2472,7 +2481,7 @@ int ext4_generic_delete_entry(handle_t *handle,
        de = (struct ext4_dir_entry_2 *)entry_buf;
        while (i < buf_size - csum_size) {
                if (ext4_check_dir_entry(dir, NULL, de, bh,
-                                        bh->b_data, bh->b_size, i))
+                                        entry_buf, buf_size, i))
                        return -EFSCORRUPTED;
                if (de == de_del)  {
                        if (pde)
@@ -2517,8 +2526,7 @@ static int ext4_delete_entry(handle_t *handle,
        if (unlikely(err))
                goto out;
 
-       err = ext4_generic_delete_entry(handle, dir, de_del,
-                                       bh, bh->b_data,
+       err = ext4_generic_delete_entry(dir, de_del, bh, bh->b_data,
                                        dir->i_sb->s_blocksize, csum_size);
        if (err)
                goto out;
@@ -3193,30 +3201,33 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
         * in separate transaction */
        retval = dquot_initialize(dir);
        if (retval)
-               return retval;
+               goto out_trace;
        retval = dquot_initialize(d_inode(dentry));
        if (retval)
-               return retval;
+               goto out_trace;
 
-       retval = -ENOENT;
        bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL);
-       if (IS_ERR(bh))
-               return PTR_ERR(bh);
-       if (!bh)
-               goto end_unlink;
+       if (IS_ERR(bh)) {
+               retval = PTR_ERR(bh);
+               goto out_trace;
+       }
+       if (!bh) {
+               retval = -ENOENT;
+               goto out_trace;
+       }
 
        inode = d_inode(dentry);
 
-       retval = -EFSCORRUPTED;
-       if (le32_to_cpu(de->inode) != inode->i_ino)
-               goto end_unlink;
+       if (le32_to_cpu(de->inode) != inode->i_ino) {
+               retval = -EFSCORRUPTED;
+               goto out_bh;
+       }
 
        handle = ext4_journal_start(dir, EXT4_HT_DIR,
                                    EXT4_DATA_TRANS_BLOCKS(dir->i_sb));
        if (IS_ERR(handle)) {
                retval = PTR_ERR(handle);
-               handle = NULL;
-               goto end_unlink;
+               goto out_bh;
        }
 
        if (IS_DIRSYNC(dir))
@@ -3224,12 +3235,12 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 
        retval = ext4_delete_entry(handle, dir, de, bh);
        if (retval)
-               goto end_unlink;
+               goto out_handle;
        dir->i_ctime = dir->i_mtime = current_time(dir);
        ext4_update_dx_flag(dir);
        retval = ext4_mark_inode_dirty(handle, dir);
        if (retval)
-               goto end_unlink;
+               goto out_handle;
        if (inode->i_nlink == 0)
                ext4_warning_inode(inode, "Deleting file '%.*s' with no links",
                                   dentry->d_name.len, dentry->d_name.name);
@@ -3251,10 +3262,11 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
                d_invalidate(dentry);
 #endif
 
-end_unlink:
+out_handle:
+       ext4_journal_stop(handle);
+out_bh:
        brelse(bh);
-       if (handle)
-               ext4_journal_stop(handle);
+out_trace:
        trace_ext4_unlink_exit(dentry, retval);
        return retval;
 }