Skip to contentSkip to conversation

ext4: Conditionally define compat ioctl numbers

PATCH In review Ben Hutchings 3 participants 7 messages May 20, 2010 – May 25, 2010 ext4 file system

lore
Share & tools
lore
#0 lore raw

PATCH 1/2 ext4: Conditionally define compat ioctl numbers

It is unnecessary, and in general impossible, to define the compat ioctl numbers except when building the filesystem with CONFIG_COMPAT defined.

---
 fs/ext4/ext4.h |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)
fs/ext4/ext4.h +2 -0
index bf938cf..f5c9941 100644
@@ -398,6 +398,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC_ALLOC_DA_BLKS		_IO('f', 12)
 #define EXT4_IOC_MOVE_EXT		_IOWR('f', 15, struct move_extent)
 
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
 /*
  * ioctl commands in 32 bit emulation
  */
@@ -413,6 +414,7 @@ struct ext4_new_group_data {
 #endif
 #define EXT4_IOC32_GETVERSION_OLD	FS_IOC32_GETVERSION
 #define EXT4_IOC32_SETVERSION_OLD	FS_IOC32_SETVERSION
+#endif
 
 
 /*
Signature · 1 line
1.7.1
#1 lore raw

PATCH 2/2 ext4: Fix compat EXT4_IOC_ADD_GROUP

struct ext4_new_group_input needs to be converted because u64 has only 32-bit alignment on some 32-bit architectures, notably i386.

---
Found and tested by myself on a Debian 2.6.32 kernel. This patch is based on linux-next.

Ben.

 fs/ext4/ext4.h  |   16 ++++++++++++++++
 fs/ext4/ioctl.c |   25 +++++++++++++++++++++++--
 2 files changed, 39 insertions(+), 2 deletions(-)
fs/ext4/ext4.h +16 -0
index f5c9941..ff540f7 100644
@@ -29,6 +29,9 @@
 #include <linux/wait.h>
 #include <linux/blockgroup_lock.h>
 #include <linux/percpu_counter.h>
+#ifdef __KERNEL__
+#include <linux/compat.h>
+#endif
 
 /*
  * The fourth extended filesystem constants/structures
@@ -332,6 +335,18 @@ struct ext4_new_group_input {
 	__u16 unused;
 };
 
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+struct compat_ext4_new_group_input {
+	u32 group;
+	compat_u64 block_bitmap;
+	compat_u64 inode_bitmap;
+	compat_u64 inode_table;
+	u32 blocks_count;
+	u16 reserved_blocks;
+	u16 unused;
+};
+#endif
+
 /* The struct ext4_new_group_input in kernel space, with free_blocks_count */
 struct ext4_new_group_data {
 	__u32 group;
@@ -409,6 +424,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC32_GETRSVSZ		_IOR('f', 5, int)
 #define EXT4_IOC32_SETRSVSZ		_IOW('f', 6, int)
 #define EXT4_IOC32_GROUP_EXTEND		_IOW('f', 7, unsigned int)
+#define EXT4_IOC32_GROUP_ADD		_IOW('f', 8, struct compat_ext4_new_group_input)
 #ifdef CONFIG_JBD2_DEBUG
 #define EXT4_IOC32_WAIT_FOR_READONLY	_IOR('f', 99, int)
 #endif
fs/ext4/ioctl.c +23 -2
index 66fa0b0..6ddec84 100644
@@ -373,8 +373,29 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case EXT4_IOC32_SETRSVSZ:
 		cmd = EXT4_IOC_SETRSVSZ;
 		break;
-	case EXT4_IOC_GROUP_ADD:
-		break;
+	case EXT4_IOC32_GROUP_ADD: {
+		struct compat_ext4_new_group_input __user *uinput;
+		struct ext4_new_group_input input;
+		mm_segment_t old_fs;
+		int err;
+
+		uinput = compat_ptr(arg);
+		err = get_user(input.group, &uinput->group);
+		err |= get_user(input.block_bitmap, &uinput->block_bitmap);
+		err |= get_user(input.inode_bitmap, &uinput->inode_bitmap);
+		err |= get_user(input.inode_table, &uinput->inode_table);
+		err |= get_user(input.blocks_count, &uinput->blocks_count);
+		err |= get_user(input.reserved_blocks,
+				&uinput->reserved_blocks);
+		if (err)
+			return -EFAULT;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD,
+				 (unsigned long) &input);
+		set_fs(old_fs);
+		return err;
+	}
 	case EXT4_IOC_MOVE_EXT:
 		break;
 	default:
Signature · 1 line
1.7.1
#2 lore raw

Re: [PATCH 2/2] ext4: Fix compat EXT4_IOC_ADD_GROUP

Quoted 2 lines · Ben Hutchings

struct ext4_new_group_input needs to be converted because u64 has only 32-bit alignment on some 32-bit architectures, notably i386.

Sigh, it would have been nice to catch this when ext4_new_group_input was first created.

I don't mind fixing the kernel, since this is clearly broken. However, we may as well go ahead and declare a new struct ext4_new_group_input that has the right alignment, rename and deprecate the old one (have resize2fs prefer the new one if available) and take the old one out in a few years. I hate this business of keeping around old cruft like this forever.

struct compat_ext4_new_group_input {
	u32 group;
	u64 block_bitmap;
	u64 inode_bitmap;
	u64 inode_table;
	u32 blocks_count;
	u16 reserved_blocks;
	u16 unused;
};
struct ext4_new_group_input {
	u64 group;
	u64 block_bitmap;
	u64 inode_bitmap;
	u64 inode_table;
	u64 blocks_count;
	u32 reserved_blocks;
        u32 unused;
};

#define EXT2_IOC_GROUP_ADD _IOW('f', 8,struct ext2_new_group_input)
#define EXT4_IOC_GROUP_ADD_OLD _IOW('f', 8,struct compat_ext4_new_group_input)
#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input)

The resize/online.c code already has compat support for both 32-bit and 64-bit IOC numbers, so it isn't much effort to have it try a third variant for a couple of years.

Quoted 63 lines
fs/ext4/ext4.h +12 -0
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+struct compat_ext4_new_group_input {
+	u32 group;
+	compat_u64 block_bitmap;
+	compat_u64 inode_bitmap;
+	compat_u64 inode_table;
+	u32 blocks_count;
+	u16 reserved_blocks;
+	u16 unused;
+};
+#endif
+

/* The struct ext4_new_group_input in kernel space, with free_blocks_count */

struct ext4_new_group_data {
	__u32 group;
fs/ext4/ext4.h +1 -0
@@ -409,6 +424,7 @@ struct ext4_new_group_data {
 #define EXT4_IOC32_GETRSVSZ		_IOR('f', 5, int)
 #define EXT4_IOC32_SETRSVSZ		_IOW('f', 6, int)
 #define EXT4_IOC32_GROUP_EXTEND		_IOW('f', 7, unsigned int)
+#define EXT4_IOC32_GROUP_ADD		_IOW('f', 8, struct compat_ext4_new_group_input)
 #ifdef CONFIG_JBD2_DEBUG
 #define EXT4_IOC32_WAIT_FOR_READONLY	_IOR('f', 99, int)
 #endif
fs/ext4/ioctl.c +23 -2
index 66fa0b0..6ddec84 100644
@@ -373,8 +373,29 @@ long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 	case EXT4_IOC32_SETRSVSZ:
 		cmd = EXT4_IOC_SETRSVSZ;
 		break;
-	case EXT4_IOC_GROUP_ADD:
-		break;
+	case EXT4_IOC32_GROUP_ADD: {
+		struct compat_ext4_new_group_input __user *uinput;
+		struct ext4_new_group_input input;
+		mm_segment_t old_fs;
+		int err;
+
+		uinput = compat_ptr(arg);
+		err = get_user(input.group, &uinput->group);
+		err |= get_user(input.block_bitmap, &uinput->block_bitmap);
+		err |= get_user(input.inode_bitmap, &uinput->inode_bitmap);
+		err |= get_user(input.inode_table, &uinput->inode_table);
+		err |= get_user(input.blocks_count, &uinput->blocks_count);
+		err |= get_user(input.reserved_blocks,
+				&uinput->reserved_blocks);
+		if (err)
+			return -EFAULT;
+		old_fs = get_fs();
+		set_fs(KERNEL_DS);
+		err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD,
+				 (unsigned long) &input);
+		set_fs(old_fs);
+		return err;
+	}
 	case EXT4_IOC_MOVE_EXT:
 		break;
 	default:
Signature · 1 line
1.7.1

Cheers, Andreas
--
Andreas Dilger
Lustre Technical Lead
Oracle Corporation Canada Inc.

#3 lore raw

Re: [PATCH 2/2] ext4: Fix compat EXT4_IOC_ADD_GROUP

Quoted 4 lines · Andreas Dilger
Quoted 2 lines · Ben Hutchings

struct ext4_new_group_input needs to be converted because u64 has only 32-bit alignment on some 32-bit architectures, notably i386.

Quoted 8 lines

Sigh, it would have been nice to catch this when ext4_new_group_input was first created.

I don't mind fixing the kernel, since this is clearly broken. However, we may as well go ahead and declare a new struct ext4_new_group_input that has the right alignment, rename and deprecate the old one (have resize2fs prefer the new one if available) and take the old one out in a few years. I hate this business of keeping around old cruft like this forever.

Well, in the long run we need a new ioctl which is compatible with flex_bg, which means doing multiple groups at once, and letting the kernel do much more of the work of selecting the block and inode numbers. And of course to support 2**64 blocks we need to support the meta_bg style of resizing. So we need to do some thinking about how to support resizing in the long-term anyway.

- Ted

#5 lore raw
In reply to Ben Hutchings
Quoted 3 lines · Ben Hutchings

It is unnecessary, and in general impossible, to define the compat ioctl numbers except when building the filesystem with CONFIG_COMPAT defined.

Umm.... why? (The impossible part) I think I'm missing something here.

- Ted

#6 lore raw
Quoted 7 lines · On Tue, May 25, 2010 at 11:15:48AM -0400, [email protected] wrote:
Quoted 3 lines · Ben Hutchings

It is unnecessary, and in general impossible, to define the compat ioctl numbers except when building the filesystem with CONFIG_COMPAT defined.

Umm.... why? (The impossible part) I think I'm missing something here.

Oh, right. The type widths might not be guaranteed (or even defined). Never mind...

- Ted