aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2007-11-14 20:00:19 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-14 21:45:43 -0500
commit7c06a8dc64a2d1884bd19b4c6353d9267ae4e3e1 (patch)
tree67afad25e4de3139d3b993e22327096c3e015013
parentdbaf4c024a657175f43b5091c4fab8b9f0e17078 (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>
-rw-r--r--fs/ext3/dir.c10
-rw-r--r--fs/ext3/namei.c92
-rw-r--r--include/linux/ext3_fs.h20
3 files changed, 70 insertions, 52 deletions
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index c8e4ee3af1d0..8ca3bfd72427 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -67,7 +67,7 @@ int ext3_check_dir_entry (const char * function, struct inode * dir,
67 unsigned long offset) 67 unsigned long offset)
68{ 68{
69 const char * error_msg = NULL; 69 const char * error_msg = NULL;
70 const int rlen = le16_to_cpu(de->rec_len); 70 const int rlen = ext3_rec_len_from_disk(de->rec_len);
71 71
72 if (rlen < EXT3_DIR_REC_LEN(1)) 72 if (rlen < EXT3_DIR_REC_LEN(1))
73 error_msg = "rec_len is smaller than minimal"; 73 error_msg = "rec_len is smaller than minimal";
@@ -173,10 +173,10 @@ revalidate:
173 * least that it is non-zero. A 173 * least that it is non-zero. A
174 * failure will be detected in the 174 * failure will be detected in the
175 * dirent test below. */ 175 * dirent test below. */
176 if (le16_to_cpu(de->rec_len) < 176 if (ext3_rec_len_from_disk(de->rec_len) <
177 EXT3_DIR_REC_LEN(1)) 177 EXT3_DIR_REC_LEN(1))
178 break; 178 break;
179 i += le16_to_cpu(de->rec_len); 179 i += ext3_rec_len_from_disk(de->rec_len);
180 } 180 }
181 offset = i; 181 offset = i;
182 filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) 182 filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
@@ -197,7 +197,7 @@ revalidate:
197 ret = stored; 197 ret = stored;
198 goto out; 198 goto out;
199 } 199 }
200 offset += le16_to_cpu(de->rec_len); 200 offset += ext3_rec_len_from_disk(de->rec_len);
201 if (le32_to_cpu(de->inode)) { 201 if (le32_to_cpu(de->inode)) {
202 /* We might block in the next section 202 /* We might block in the next section
203 * if the data destination is 203 * if the data destination is
@@ -219,7 +219,7 @@ revalidate:
219 goto revalidate; 219 goto revalidate;
220 stored ++; 220 stored ++;
221 } 221 }
222 filp->f_pos += le16_to_cpu(de->rec_len); 222 filp->f_pos += ext3_rec_len_from_disk(de->rec_len);
223 } 223 }
224 offset = 0; 224 offset = 0;
225 brelse (bh); 225 brelse (bh);
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 */
182static inline struct ext3_dir_entry_2 *
183ext3_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 */
552static 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
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 64134456ed8c..241c01cb92b2 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -656,6 +656,26 @@ struct ext3_dir_entry_2 {
656#define EXT3_DIR_ROUND (EXT3_DIR_PAD - 1) 656#define EXT3_DIR_ROUND (EXT3_DIR_PAD - 1)
657#define EXT3_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT3_DIR_ROUND) & \ 657#define EXT3_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT3_DIR_ROUND) & \
658 ~EXT3_DIR_ROUND) 658 ~EXT3_DIR_ROUND)
659#define EXT3_MAX_REC_LEN ((1<<16)-1)
660
661static inline unsigned ext3_rec_len_from_disk(__le16 dlen)
662{
663 unsigned len = le16_to_cpu(dlen);
664
665 if (len == EXT3_MAX_REC_LEN)
666 return 1 << 16;
667 return len;
668}
669
670static inline __le16 ext3_rec_len_to_disk(unsigned len)
671{
672 if (len == (1 << 16))
673 return cpu_to_le16(EXT3_MAX_REC_LEN);
674 else if (len > (1 << 16))
675 BUG();
676 return cpu_to_le16(len);
677}
678
659/* 679/*
660 * Hash Tree Directory indexing 680 * Hash Tree Directory indexing
661 * (c) Daniel Phillips, 2001 681 * (c) Daniel Phillips, 2001