diff options
author | Jan Kara <jack@suse.cz> | 2007-11-14 20:00:19 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-14 21:45:43 -0500 |
commit | 7c06a8dc64a2d1884bd19b4c6353d9267ae4e3e1 (patch) | |
tree | 67afad25e4de3139d3b993e22327096c3e015013 /fs/ext3/namei.c | |
parent | dbaf4c024a657175f43b5091c4fab8b9f0e17078 (diff) |
Fix 64KB blocksize in ext3 directories
With 64KB blocksize, a directory entry can have size 64KB which does not
fit into 16 bits we have for entry lenght. So we store 0xffff instead and
convert value when read from / written to disk. The patch also converts
some places to use ext3_next_entry() when we are changing them anyway.
[akpm@linux-foundation.org: coding-style cleanups]
Signed-off-by: Jan Kara <jack@suse.cz>
Cc: <linux-ext4@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ext3/namei.c')
-rw-r--r-- | fs/ext3/namei.c | 92 |
1 files changed, 45 insertions, 47 deletions
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index ec8170adac53..4ab6f76e63d0 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
@@ -177,6 +177,16 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
177 | struct inode *inode); | 177 | struct inode *inode); |
178 | 178 | ||
179 | /* | 179 | /* |
180 | * p is at least 6 bytes before the end of page | ||
181 | */ | ||
182 | static inline struct ext3_dir_entry_2 * | ||
183 | ext3_next_entry(struct ext3_dir_entry_2 *p) | ||
184 | { | ||
185 | return (struct ext3_dir_entry_2 *)((char *)p + | ||
186 | ext3_rec_len_from_disk(p->rec_len)); | ||
187 | } | ||
188 | |||
189 | /* | ||
180 | * Future: use high four bits of block for coalesce-on-delete flags | 190 | * Future: use high four bits of block for coalesce-on-delete flags |
181 | * Mask them off for now. | 191 | * Mask them off for now. |
182 | */ | 192 | */ |
@@ -280,7 +290,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_ent | |||
280 | space += EXT3_DIR_REC_LEN(de->name_len); | 290 | space += EXT3_DIR_REC_LEN(de->name_len); |
281 | names++; | 291 | names++; |
282 | } | 292 | } |
283 | de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); | 293 | de = ext3_next_entry(de); |
284 | } | 294 | } |
285 | printk("(%i)\n", names); | 295 | printk("(%i)\n", names); |
286 | return (struct stats) { names, space, 1 }; | 296 | return (struct stats) { names, space, 1 }; |
@@ -547,14 +557,6 @@ static int ext3_htree_next_block(struct inode *dir, __u32 hash, | |||
547 | 557 | ||
548 | 558 | ||
549 | /* | 559 | /* |
550 | * p is at least 6 bytes before the end of page | ||
551 | */ | ||
552 | static inline struct ext3_dir_entry_2 *ext3_next_entry(struct ext3_dir_entry_2 *p) | ||
553 | { | ||
554 | return (struct ext3_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len)); | ||
555 | } | ||
556 | |||
557 | /* | ||
558 | * This function fills a red-black tree with information from a | 560 | * This function fills a red-black tree with information from a |
559 | * directory block. It returns the number directory entries loaded | 561 | * directory block. It returns the number directory entries loaded |
560 | * into the tree. If there is an error it is returned in err. | 562 | * into the tree. If there is an error it is returned in err. |
@@ -720,7 +722,7 @@ static int dx_make_map (struct ext3_dir_entry_2 *de, int size, | |||
720 | cond_resched(); | 722 | cond_resched(); |
721 | } | 723 | } |
722 | /* XXX: do we need to check rec_len == 0 case? -Chris */ | 724 | /* XXX: do we need to check rec_len == 0 case? -Chris */ |
723 | de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len)); | 725 | de = ext3_next_entry(de); |
724 | } | 726 | } |
725 | return count; | 727 | return count; |
726 | } | 728 | } |
@@ -822,7 +824,7 @@ static inline int search_dirblock(struct buffer_head * bh, | |||
822 | return 1; | 824 | return 1; |
823 | } | 825 | } |
824 | /* prevent looping on a bad block */ | 826 | /* prevent looping on a bad block */ |
825 | de_len = le16_to_cpu(de->rec_len); | 827 | de_len = ext3_rec_len_from_disk(de->rec_len); |
826 | if (de_len <= 0) | 828 | if (de_len <= 0) |
827 | return -1; | 829 | return -1; |
828 | offset += de_len; | 830 | offset += de_len; |
@@ -1130,7 +1132,7 @@ dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count) | |||
1130 | rec_len = EXT3_DIR_REC_LEN(de->name_len); | 1132 | rec_len = EXT3_DIR_REC_LEN(de->name_len); |
1131 | memcpy (to, de, rec_len); | 1133 | memcpy (to, de, rec_len); |
1132 | ((struct ext3_dir_entry_2 *) to)->rec_len = | 1134 | ((struct ext3_dir_entry_2 *) to)->rec_len = |
1133 | cpu_to_le16(rec_len); | 1135 | ext3_rec_len_to_disk(rec_len); |
1134 | de->inode = 0; | 1136 | de->inode = 0; |
1135 | map++; | 1137 | map++; |
1136 | to += rec_len; | 1138 | to += rec_len; |
@@ -1149,13 +1151,12 @@ static struct ext3_dir_entry_2* dx_pack_dirents(char *base, int size) | |||
1149 | 1151 | ||
1150 | prev = to = de; | 1152 | prev = to = de; |
1151 | while ((char*)de < base + size) { | 1153 | while ((char*)de < base + size) { |
1152 | next = (struct ext3_dir_entry_2 *) ((char *) de + | 1154 | next = ext3_next_entry(de); |
1153 | le16_to_cpu(de->rec_len)); | ||
1154 | if (de->inode && de->name_len) { | 1155 | if (de->inode && de->name_len) { |
1155 | rec_len = EXT3_DIR_REC_LEN(de->name_len); | 1156 | rec_len = EXT3_DIR_REC_LEN(de->name_len); |
1156 | if (de > to) | 1157 | if (de > to) |
1157 | memmove(to, de, rec_len); | 1158 | memmove(to, de, rec_len); |
1158 | to->rec_len = cpu_to_le16(rec_len); | 1159 | to->rec_len = ext3_rec_len_to_disk(rec_len); |
1159 | prev = to; | 1160 | prev = to; |
1160 | to = (struct ext3_dir_entry_2 *) (((char *) to) + rec_len); | 1161 | to = (struct ext3_dir_entry_2 *) (((char *) to) + rec_len); |
1161 | } | 1162 | } |
@@ -1229,8 +1230,8 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, | |||
1229 | /* Fancy dance to stay within two buffers */ | 1230 | /* Fancy dance to stay within two buffers */ |
1230 | de2 = dx_move_dirents(data1, data2, map + split, count - split); | 1231 | de2 = dx_move_dirents(data1, data2, map + split, count - split); |
1231 | de = dx_pack_dirents(data1,blocksize); | 1232 | de = dx_pack_dirents(data1,blocksize); |
1232 | de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de); | 1233 | de->rec_len = ext3_rec_len_to_disk(data1 + blocksize - (char *) de); |
1233 | de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2); | 1234 | de2->rec_len = ext3_rec_len_to_disk(data2 + blocksize - (char *) de2); |
1234 | dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1)); | 1235 | dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1)); |
1235 | dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1)); | 1236 | dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1)); |
1236 | 1237 | ||
@@ -1300,7 +1301,7 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1300 | return -EEXIST; | 1301 | return -EEXIST; |
1301 | } | 1302 | } |
1302 | nlen = EXT3_DIR_REC_LEN(de->name_len); | 1303 | nlen = EXT3_DIR_REC_LEN(de->name_len); |
1303 | rlen = le16_to_cpu(de->rec_len); | 1304 | rlen = ext3_rec_len_from_disk(de->rec_len); |
1304 | if ((de->inode? rlen - nlen: rlen) >= reclen) | 1305 | if ((de->inode? rlen - nlen: rlen) >= reclen) |
1305 | break; | 1306 | break; |
1306 | de = (struct ext3_dir_entry_2 *)((char *)de + rlen); | 1307 | de = (struct ext3_dir_entry_2 *)((char *)de + rlen); |
@@ -1319,11 +1320,11 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1319 | 1320 | ||
1320 | /* By now the buffer is marked for journaling */ | 1321 | /* By now the buffer is marked for journaling */ |
1321 | nlen = EXT3_DIR_REC_LEN(de->name_len); | 1322 | nlen = EXT3_DIR_REC_LEN(de->name_len); |
1322 | rlen = le16_to_cpu(de->rec_len); | 1323 | rlen = ext3_rec_len_from_disk(de->rec_len); |
1323 | if (de->inode) { | 1324 | if (de->inode) { |
1324 | struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen); | 1325 | struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen); |
1325 | de1->rec_len = cpu_to_le16(rlen - nlen); | 1326 | de1->rec_len = ext3_rec_len_to_disk(rlen - nlen); |
1326 | de->rec_len = cpu_to_le16(nlen); | 1327 | de->rec_len = ext3_rec_len_to_disk(nlen); |
1327 | de = de1; | 1328 | de = de1; |
1328 | } | 1329 | } |
1329 | de->file_type = EXT3_FT_UNKNOWN; | 1330 | de->file_type = EXT3_FT_UNKNOWN; |
@@ -1400,17 +1401,18 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, | |||
1400 | 1401 | ||
1401 | /* The 0th block becomes the root, move the dirents out */ | 1402 | /* The 0th block becomes the root, move the dirents out */ |
1402 | fde = &root->dotdot; | 1403 | fde = &root->dotdot; |
1403 | de = (struct ext3_dir_entry_2 *)((char *)fde + le16_to_cpu(fde->rec_len)); | 1404 | de = (struct ext3_dir_entry_2 *)((char *)fde + |
1405 | ext3_rec_len_from_disk(fde->rec_len)); | ||
1404 | len = ((char *) root) + blocksize - (char *) de; | 1406 | len = ((char *) root) + blocksize - (char *) de; |
1405 | memcpy (data1, de, len); | 1407 | memcpy (data1, de, len); |
1406 | de = (struct ext3_dir_entry_2 *) data1; | 1408 | de = (struct ext3_dir_entry_2 *) data1; |
1407 | top = data1 + len; | 1409 | top = data1 + len; |
1408 | while ((char *)(de2=(void*)de+le16_to_cpu(de->rec_len)) < top) | 1410 | while ((char *)(de2 = ext3_next_entry(de)) < top) |
1409 | de = de2; | 1411 | de = de2; |
1410 | de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de); | 1412 | de->rec_len = ext3_rec_len_to_disk(data1 + blocksize - (char *) de); |
1411 | /* Initialize the root; the dot dirents already exist */ | 1413 | /* Initialize the root; the dot dirents already exist */ |
1412 | de = (struct ext3_dir_entry_2 *) (&root->dotdot); | 1414 | de = (struct ext3_dir_entry_2 *) (&root->dotdot); |
1413 | de->rec_len = cpu_to_le16(blocksize - EXT3_DIR_REC_LEN(2)); | 1415 | de->rec_len = ext3_rec_len_to_disk(blocksize - EXT3_DIR_REC_LEN(2)); |
1414 | memset (&root->info, 0, sizeof(root->info)); | 1416 | memset (&root->info, 0, sizeof(root->info)); |
1415 | root->info.info_length = sizeof(root->info); | 1417 | root->info.info_length = sizeof(root->info); |
1416 | root->info.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; | 1418 | root->info.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; |
@@ -1490,7 +1492,7 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry, | |||
1490 | return retval; | 1492 | return retval; |
1491 | de = (struct ext3_dir_entry_2 *) bh->b_data; | 1493 | de = (struct ext3_dir_entry_2 *) bh->b_data; |
1492 | de->inode = 0; | 1494 | de->inode = 0; |
1493 | de->rec_len = cpu_to_le16(blocksize); | 1495 | de->rec_len = ext3_rec_len_to_disk(blocksize); |
1494 | return add_dirent_to_buf(handle, dentry, inode, de, bh); | 1496 | return add_dirent_to_buf(handle, dentry, inode, de, bh); |
1495 | } | 1497 | } |
1496 | 1498 | ||
@@ -1553,7 +1555,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, | |||
1553 | goto cleanup; | 1555 | goto cleanup; |
1554 | node2 = (struct dx_node *)(bh2->b_data); | 1556 | node2 = (struct dx_node *)(bh2->b_data); |
1555 | entries2 = node2->entries; | 1557 | entries2 = node2->entries; |
1556 | node2->fake.rec_len = cpu_to_le16(sb->s_blocksize); | 1558 | node2->fake.rec_len = ext3_rec_len_to_disk(sb->s_blocksize); |
1557 | node2->fake.inode = 0; | 1559 | node2->fake.inode = 0; |
1558 | BUFFER_TRACE(frame->bh, "get_write_access"); | 1560 | BUFFER_TRACE(frame->bh, "get_write_access"); |
1559 | err = ext3_journal_get_write_access(handle, frame->bh); | 1561 | err = ext3_journal_get_write_access(handle, frame->bh); |
@@ -1651,9 +1653,9 @@ static int ext3_delete_entry (handle_t *handle, | |||
1651 | BUFFER_TRACE(bh, "get_write_access"); | 1653 | BUFFER_TRACE(bh, "get_write_access"); |
1652 | ext3_journal_get_write_access(handle, bh); | 1654 | ext3_journal_get_write_access(handle, bh); |
1653 | if (pde) | 1655 | if (pde) |
1654 | pde->rec_len = | 1656 | pde->rec_len = ext3_rec_len_to_disk( |
1655 | cpu_to_le16(le16_to_cpu(pde->rec_len) + | 1657 | ext3_rec_len_from_disk(pde->rec_len) + |
1656 | le16_to_cpu(de->rec_len)); | 1658 | ext3_rec_len_from_disk(de->rec_len)); |
1657 | else | 1659 | else |
1658 | de->inode = 0; | 1660 | de->inode = 0; |
1659 | dir->i_version++; | 1661 | dir->i_version++; |
@@ -1661,10 +1663,9 @@ static int ext3_delete_entry (handle_t *handle, | |||
1661 | ext3_journal_dirty_metadata(handle, bh); | 1663 | ext3_journal_dirty_metadata(handle, bh); |
1662 | return 0; | 1664 | return 0; |
1663 | } | 1665 | } |
1664 | i += le16_to_cpu(de->rec_len); | 1666 | i += ext3_rec_len_from_disk(de->rec_len); |
1665 | pde = de; | 1667 | pde = de; |
1666 | de = (struct ext3_dir_entry_2 *) | 1668 | de = ext3_next_entry(de); |
1667 | ((char *) de + le16_to_cpu(de->rec_len)); | ||
1668 | } | 1669 | } |
1669 | return -ENOENT; | 1670 | return -ENOENT; |
1670 | } | 1671 | } |
@@ -1798,13 +1799,13 @@ retry: | |||
1798 | de = (struct ext3_dir_entry_2 *) dir_block->b_data; | 1799 | de = (struct ext3_dir_entry_2 *) dir_block->b_data; |
1799 | de->inode = cpu_to_le32(inode->i_ino); | 1800 | de->inode = cpu_to_le32(inode->i_ino); |
1800 | de->name_len = 1; | 1801 | de->name_len = 1; |
1801 | de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(de->name_len)); | 1802 | de->rec_len = ext3_rec_len_to_disk(EXT3_DIR_REC_LEN(de->name_len)); |
1802 | strcpy (de->name, "."); | 1803 | strcpy (de->name, "."); |
1803 | ext3_set_de_type(dir->i_sb, de, S_IFDIR); | 1804 | ext3_set_de_type(dir->i_sb, de, S_IFDIR); |
1804 | de = (struct ext3_dir_entry_2 *) | 1805 | de = ext3_next_entry(de); |
1805 | ((char *) de + le16_to_cpu(de->rec_len)); | ||
1806 | de->inode = cpu_to_le32(dir->i_ino); | 1806 | de->inode = cpu_to_le32(dir->i_ino); |
1807 | de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT3_DIR_REC_LEN(1)); | 1807 | de->rec_len = ext3_rec_len_to_disk(inode->i_sb->s_blocksize - |
1808 | EXT3_DIR_REC_LEN(1)); | ||
1808 | de->name_len = 2; | 1809 | de->name_len = 2; |
1809 | strcpy (de->name, ".."); | 1810 | strcpy (de->name, ".."); |
1810 | ext3_set_de_type(dir->i_sb, de, S_IFDIR); | 1811 | ext3_set_de_type(dir->i_sb, de, S_IFDIR); |
@@ -1856,8 +1857,7 @@ static int empty_dir (struct inode * inode) | |||
1856 | return 1; | 1857 | return 1; |
1857 | } | 1858 | } |
1858 | de = (struct ext3_dir_entry_2 *) bh->b_data; | 1859 | de = (struct ext3_dir_entry_2 *) bh->b_data; |
1859 | de1 = (struct ext3_dir_entry_2 *) | 1860 | de1 = ext3_next_entry(de); |
1860 | ((char *) de + le16_to_cpu(de->rec_len)); | ||
1861 | if (le32_to_cpu(de->inode) != inode->i_ino || | 1861 | if (le32_to_cpu(de->inode) != inode->i_ino || |
1862 | !le32_to_cpu(de1->inode) || | 1862 | !le32_to_cpu(de1->inode) || |
1863 | strcmp (".", de->name) || | 1863 | strcmp (".", de->name) || |
@@ -1868,9 +1868,9 @@ static int empty_dir (struct inode * inode) | |||
1868 | brelse (bh); | 1868 | brelse (bh); |
1869 | return 1; | 1869 | return 1; |
1870 | } | 1870 | } |
1871 | offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); | 1871 | offset = ext3_rec_len_from_disk(de->rec_len) + |
1872 | de = (struct ext3_dir_entry_2 *) | 1872 | ext3_rec_len_from_disk(de1->rec_len); |
1873 | ((char *) de1 + le16_to_cpu(de1->rec_len)); | 1873 | de = ext3_next_entry(de1); |
1874 | while (offset < inode->i_size ) { | 1874 | while (offset < inode->i_size ) { |
1875 | if (!bh || | 1875 | if (!bh || |
1876 | (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { | 1876 | (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { |
@@ -1899,9 +1899,8 @@ static int empty_dir (struct inode * inode) | |||
1899 | brelse (bh); | 1899 | brelse (bh); |
1900 | return 0; | 1900 | return 0; |
1901 | } | 1901 | } |
1902 | offset += le16_to_cpu(de->rec_len); | 1902 | offset += ext3_rec_len_from_disk(de->rec_len); |
1903 | de = (struct ext3_dir_entry_2 *) | 1903 | de = ext3_next_entry(de); |
1904 | ((char *) de + le16_to_cpu(de->rec_len)); | ||
1905 | } | 1904 | } |
1906 | brelse (bh); | 1905 | brelse (bh); |
1907 | return 1; | 1906 | return 1; |
@@ -2255,8 +2254,7 @@ retry: | |||
2255 | } | 2254 | } |
2256 | 2255 | ||
2257 | #define PARENT_INO(buffer) \ | 2256 | #define PARENT_INO(buffer) \ |
2258 | ((struct ext3_dir_entry_2 *) ((char *) buffer + \ | 2257 | (ext3_next_entry((struct ext3_dir_entry_2 *)(buffer))->inode) |
2259 | le16_to_cpu(((struct ext3_dir_entry_2 *) buffer)->rec_len)))->inode | ||
2260 | 2258 | ||
2261 | /* | 2259 | /* |
2262 | * Anybody can rename anything with this: the permission checks are left to the | 2260 | * Anybody can rename anything with this: the permission checks are left to the |