2007-09-25 16:26:48

by Jan Kara

[permalink] [raw]
Subject: [PATCH] Support for 64KB blocksize in e2fsprogs

Hi,

attached patch implements support for 64KB blocksize in directories in
e2fsprogs. This patch complements the kernel patches for ext2-4 I've sent
yesterday. Ted, does the patch look fine?
Honza

--
Jan Kara <[email protected]>
SUSE Labs, CR

-----

Subject: Support for 64KB blocksize in ext2-4 directories.

When block size is 64KB, we have to take care that rec_len does not overflow.
Kernel stores 0xffff in case 0x10000 should be stored - perform appropriate
conversion when reading from / writing to disk.

Signed-off-by: Jan Kara <[email protected]>

diff --git a/lib/ext2fs/dirblock.c b/lib/ext2fs/dirblock.c
index fb20fa0..628bf93 100644
--- a/lib/ext2fs/dirblock.c
+++ b/lib/ext2fs/dirblock.c
@@ -38,9 +38,9 @@ errcode_t ext2fs_read_dir_block2(ext2_fi
dirent = (struct ext2_dir_entry *) p;
#ifdef WORDS_BIGENDIAN
dirent->inode = ext2fs_swab32(dirent->inode);
- dirent->rec_len = ext2fs_swab16(dirent->rec_len);
dirent->name_len = ext2fs_swab16(dirent->name_len);
#endif
+ dirent->rec_len = ext2fs_rec_len_from_disk(dirent->rec_len);
name_len = dirent->name_len;
#ifdef WORDS_BIGENDIAN
if (flags & EXT2_DIRBLOCK_V2_STRUCT)
@@ -68,12 +68,15 @@ errcode_t ext2fs_read_dir_block(ext2_fil
errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
void *inbuf, int flags EXT2FS_ATTR((unused)))
{
-#ifdef WORDS_BIGENDIAN
errcode_t retval;
char *p, *end;
char *buf = 0;
struct ext2_dir_entry *dirent;

+#ifndef WORDS_BIGENDIAN
+ if (fs->blocksize < EXT2_MAX_REC_LEN)
+ goto just_write;
+#endif
retval = ext2fs_get_mem(fs->blocksize, &buf);
if (retval)
return retval;
@@ -89,7 +92,7 @@ errcode_t ext2fs_write_dir_block2(ext2_f
}
p += dirent->rec_len;
dirent->inode = ext2fs_swab32(dirent->inode);
- dirent->rec_len = ext2fs_swab16(dirent->rec_len);
+ dirent->rec_len = ext2fs_rec_len_to_disk(dirent->rec_len);
dirent->name_len = ext2fs_swab16(dirent->name_len);

if (flags & EXT2_DIRBLOCK_V2_STRUCT)
@@ -98,9 +101,8 @@ errcode_t ext2fs_write_dir_block2(ext2_f
retval = io_channel_write_blk(fs->io, block, 1, buf);
ext2fs_free_mem(&buf);
return retval;
-#else
+just_write:
return io_channel_write_blk(fs->io, block, 1, (char *) inbuf);
-#endif
}


diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
index a316665..2041f0f 100644
--- a/lib/ext2fs/ext2_fs.h
+++ b/lib/ext2fs/ext2_fs.h
@@ -717,6 +717,32 @@ struct ext2_dir_entry_2 {
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
~EXT2_DIR_ROUND)
+#define EXT2_MAX_REC_LEN ((1<<16)-1)
+
+static inline unsigned ext2fs_rec_len_from_disk(unsigned len)
+{
+#ifdef WORDS_BIGENDIAN
+ len = ext2fs_swab16(dlen);
+#endif
+ if (len == EXT2_MAX_REC_LEN)
+ return 1 << 16;
+ return len;
+}
+
+static inline unsigned ext2fs_rec_len_to_disk(unsigned len)
+{
+ if (len == (1 << 16))
+#ifdef WORDS_BIGENDIAN
+ return ext2fs_swab16(EXT2_MAX_REC_LEN);
+#else
+ return EXT2_MAX_REC_LEN;
+#endif
+#ifdef WORDS_BIGENDIAN
+ return ext2fs_swab_16(len);
+#else
+ return len;
+#endif
+}

/*
* This structure will be used for multiple mount protection. It will be
diff --git a/misc/e2image.c b/misc/e2image.c
index 1fbb267..4e2c9fb 100644
--- a/misc/e2image.c
+++ b/misc/e2image.c
@@ -345,10 +345,7 @@ static void scramble_dir_block(ext2_fils
end = buf + fs->blocksize;
for (p = buf; p < end-8; p += rec_len) {
dirent = (struct ext2_dir_entry_2 *) p;
- rec_len = dirent->rec_len;
-#ifdef WORDS_BIGENDIAN
- rec_len = ext2fs_swab16(rec_len);
-#endif
+ rec_len = ext2fs_rec_len_from_disk(dirent->rec_len);
#if 0
printf("rec_len = %d, name_len = %d\n", rec_len, dirent->name_len);
#endif
@@ -358,9 +355,7 @@ static void scramble_dir_block(ext2_fils
"bad rec_len (%d)\n", (unsigned long) blk,
rec_len);
rec_len = end - p;
-#ifdef WORDS_BIGENDIAN
- dirent->rec_len = ext2fs_swab16(rec_len);
-#endif
+ dirent->rec_len = ext2fs_rec_len_to_disk(rec_len);
continue;
}
if (dirent->name_len + 8 > rec_len) {