* 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. */
| 1705 | * Returns pointer to de in block into which the new entry will be inserted. |
| 1706 | */ |
| 1707 | struct ext3_dir_entry_2 * |
| 1708 | do_split(struct ext2_icb *icb, struct inode *dir, |
| 1709 | struct buffer_head **bh,struct dx_frame *frame, |
| 1710 | struct dx_hash_info *hinfo, int *error) |
| 1711 | { |
| 1712 | unsigned blocksize = dir->i_sb->s_blocksize; |
| 1713 | unsigned count, continued; |
| 1714 | struct buffer_head *bh2; |
| 1715 | u32 newblock; |
| 1716 | u32 hash2; |
| 1717 | struct dx_map_entry *map; |
| 1718 | char *data1 = (*bh)->b_data, *data2; |
| 1719 | unsigned split, move, size; |
| 1720 | struct ext3_dir_entry_2 *de = NULL, *de2; |
| 1721 | struct ext4_dir_entry_tail *t; |
| 1722 | int csum_size = 0; |
| 1723 | int err, i; |
| 1724 | |
| 1725 | if (ext4_has_metadata_csum(dir->i_sb)) |
| 1726 | csum_size = sizeof(struct ext4_dir_entry_tail); |
| 1727 | |
| 1728 | bh2 = ext3_append (icb, dir, &newblock, error); |
| 1729 | if (!(bh2)) { |
| 1730 | brelse(*bh); |
| 1731 | *bh = NULL; |
| 1732 | goto errout; |
| 1733 | } |
| 1734 | |
| 1735 | data2 = bh2->b_data; |
| 1736 | |
| 1737 | /* create map in the end of data2 block */ |
| 1738 | map = (struct dx_map_entry *) (data2 + blocksize); |
| 1739 | count = dx_make_map ((struct ext3_dir_entry_2 *) data1, |
| 1740 | blocksize, hinfo, map); |
| 1741 | map -= count; |
| 1742 | dx_sort_map (map, count); |
| 1743 | /* Split the existing block in the middle, size-wise */ |
| 1744 | size = 0; |
| 1745 | move = 0; |
| 1746 | for (i = count-1; i >= 0; i--) { |
| 1747 | /* is more than half of this entry in 2nd half of the block? */ |
| 1748 | if (size + map[i].size/2 > blocksize/2) |
| 1749 | break; |
| 1750 | size += map[i].size; |
| 1751 | move++; |
| 1752 | } |
| 1753 | /* map index at which we will split */ |
| 1754 | split = count - move; |
| 1755 | hash2 = map[split].hash; |
| 1756 | continued = hash2 == map[split - 1].hash; |
| 1757 | dxtrace(printk("Split block %i at %x, %i/%i\n", |
| 1758 | dx_get_block(frame->at), hash2, split, count-split)); |
| 1759 | |
| 1760 | /* Fancy dance to stay within two buffers */ |
| 1761 | de2 = dx_move_dirents(data1, data2, map + split, count - split); |
| 1762 | de = dx_pack_dirents(data1,blocksize); |
| 1763 | de->rec_len = cpu_to_le16(data1 + (blocksize - csum_size) - (char *) de); |
| 1764 | de2->rec_len = cpu_to_le16(data2 + (blocksize - csum_size) - (char *) de2); |
no test coverage detected