其他分享
首页 > 其他分享> > Email-reading: Add ioctls to get/set the ext4 superblock uuid

Email-reading: Add ioctls to get/set the ext4 superblock uuid

作者:互联网

Origin Patch[PATCH] Add ioctls to get/set the ext4 superblock uuid.

Note1: Userspace abi change should cc more

This is a userspace abi change; it really should cc linux-fsdevel and linux-api.

Patch 增加了 EXT4_IOC_GETFSUUID 以及对应的 SET 接口,因此抄送 linux-api。另外 比较大的 fs 修改需要抄送 linux-fsdevel

另外如果对用户使用有修改,需要修改 man 手册:[PATCH] Add support for get/set UUID ioctls.

如果可以的话,增加 fstest 测试用例:[PATCH] ext4/056: add a check to make sure ext4 uuid ioctls get/set during fsstress.

Note2: Direction is a separate part in the ioctl command value

+#define EXT4_IOC_GETFSUUID		_IOR('f', 44, struct fsuuid)
+#define EXT4_IOC_SETFSUUID		_IOW('f', 45, struct fsuuid)

One thing I've noticed people rarely do with a get/set ioctl pair -- the _IOR and _IOW macros encode the direction (R/W) in the ioctl number, which means that you don't need to use both 44 and 45 here. We get 8 bits of namespace ('f') and 8 bits of call number (44), and while they're generally not in /that/ short supply, a u16 will eventually fill up.
If you want to be paranoid, you could also encode a BUILD_BUG_ON to check that they're not the same.

ioctl 请求编号是 32 位产量,通常通过 <asm/ioctl.h> 中定义的宏来构建[1]。下表描述了各 bit 的含义(和代码里有些出入,以理解为主):

0-8 bits 9-16 bits 17-24 bits 25-32 bits
number magic arg size direction

可以看到 direction 域包含了 ioctl 的方向。因此 EXT4_IOC_GETFSUUID 和 EXT4_IOC_SETFSUUID 完全可以用一个 number。

# define _IOC_WRITE	1U
# define _IOC_READ	2U

#define _IOC(dir,type,nr,size) \
	(((dir)  << _IOC_DIRSHIFT) | \
	 ((type) << _IOC_TYPESHIFT) | \
	 ((nr)   << _IOC_NRSHIFT) | \
	 ((size) << _IOC_SIZESHIFT))

#define _IOR(type,nr,size)	_IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size)))
#define _IOW(type,nr,size)	_IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

Note3: Use explicitly sized menber (ioctl)

+struct fsuuid {
+	size_t len;

size_t... is a mess for userspace ABI. If the kernel is running in a multiarch environment (e.g. i386 program running on x64 kernel) then you'll have to make sure that the field length is what you think it is. Given the current typedef hell w.r.t. size_t, I suggest making life easier on the reviewers and making @len explicitly sized.
Also, please put in a @flags argument just in case someone someday needs to add some.

Note 4: Use unsized VLA instead of a pointer (ioctl)

+	__u8 __user *b;

Putting a pointer in an ioctl struct argument is a /very/ bad idea, because doing so (a) makes it harder for things like seccomp to inspect arguments, and (b) usually means you have to implement a bunch of fugly compat ioctl thunking code for multiarch systems (e.g. i386 program running on x64 kernel) to extract the pointer and convert it to a native pointer.

You /could/ avoid both of these problems by requiring that the uuid data be stored in an unsized VLA at the end of the struct:

	struct fsuuid {
		__u32	fu_len;
		__u32	fu_flags;

		__u8	fu_uuid[];
	};

Then your set uuid validation code looks like this:

	int ret = 0;
	__u8 uuid[UUID_SIZE];
	struct fsuuid fsuuid;

	if (copy_from_user(&fsuuid, ufsuuid, sizeof(fsuuid)))
		return -EFAULT;

	if (fsuuid.fu_flags || fsuuid.fu_len != UUID_SIZE)
		return -EINVAL;

	if (copy_from_user(uuid, &fsuuid.fu_uuid[0], UUID_SIZE))
		return -EFAULT;

	/* actually set uuid... */

零长数组的使用,参考 Zero Length (Using the GNU Compiler Collection (GCC))


V2 Patch[PATCH v2] Add ioctls to get/set the ext4 superblock uuid.

Question1: __user 应该怎么用?有什么用?

+struct fsuuid {
+	__u32       fu_len;
+	__u32       fu_flags;
+	__u8 __user fu_uuid[];

__user is unnecessary here -- it applies to pointers, not to struct members.

sparse 工具 [2] 使用 __user 检查是否对用户空间指针存在解引用的情况,所以应用对象是指针。

__user 定义如下,这里的 address_space 指的是真正的地址空间,而不是 fs 里那个冒牌货 :p。另外 address_space(__user) 这样的表述很奇怪,追踪了下是 18 年 sparse 支持根据标识符定义 address_space 了,所以有人把原来的 address_space(1) 改成了现在这样 [3]

另外关于其他宏的用法可以参考 聊一聊linux内核中的基础工具库(2) Sparse - 知乎

/* sparse defines __CHECKER__; see Documentation/dev-tools/sparse.rst */
#ifdef __CHECKER__
/* address spaces */
# define __kernel	__attribute__((address_space(0)))
# define __user		__attribute__((noderef, address_space(__user)))
# define __iomem	__attribute__((noderef, address_space(__iomem)))
# define __percpu	__attribute__((noderef, address_space(__percpu)))
# define __rcu		__attribute__((noderef, address_space(__rcu)))

  1. ioctl(2) - Linux manual page ↩︎

  2. Sparse: a look under the hood [LWN.net] ↩︎

  3. sparse: use identifiers to define address spaces - Linux kernel source tree ↩︎

标签:__,set,uuid,fsuuid,get,user,address,define
来源: https://www.cnblogs.com/liuchao719/p/Email-reading-22_07_07.html