环回设备是一种特殊的块设备,它允许你将一个普通的文件当作块设备来使用。这种功能在需要将文件系统挂载到一个文件上时特别有用,比如在处理磁盘镜像文件时。
内核驱动:drivers/block/loop.c。 在内核驱动初始化时会自动创建一定数量的loop设备,上层在通过/dev/loop-control节点ioctrl LOOP_CTL_GET_FREE时,如果没有设备会自动创建。
在ramdisk init阶段需要创建/dev/loop-control和/dev/block/loop0-3节点,并绑定内核环回设备:
c
system/core$
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index d050ed783..b34003635 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -233,7 +233,7 @@ int FirstStageMain(int argc, char** argv) {
CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1));
// Get the basic filesystem setup we need put together in the initramdisk
// on / and then we'll let the rc file figure out the rest.
- CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
+ CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755,size=1024M"));
CHECKCALL(mkdir("/dev/pts", 0755));
CHECKCALL(mkdir("/dev/socket", 0755));
CHECKCALL(mkdir("/dev/dm-user", 0755));
@@ -266,6 +266,12 @@ int FirstStageMain(int argc, char** argv) {
// This is needed for log wrapper, which gets called before ueventd runs.
CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2)));
CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3)));
+ CHECKCALL(mknod("/dev/loop-control", S_IFCHR | 0666, makedev(10, 237)));
+ CHECKCALL(mkdir("/dev/block", 0755));
+ CHECKCALL(mknod("/dev/block/loop0", S_IFBLK | 0755, makedev(7, 0)));
+ CHECKCALL(mknod("/dev/block/loop1", S_IFBLK | 0755, makedev(7, 8)));
+ CHECKCALL(mknod("/dev/block/loop2", S_IFBLK | 0755, makedev(7, 16)));
+ CHECKCALL(mknod("/dev/block/loop3", S_IFBLK | 0755, makedev(7, 24)));
-
mknod(const char *pathname, mode_t mode, dev_t dev)
是一个系统调用,用于创建一个文件系统节点(文件、设备特殊文件或命名管道)。 -
参数解释:
"/dev/block/loop0"
:这是要创建的设备文件的路径。S_IFBLK | 0755
:这是文件的模式。S_IFBLK
表示创建的是一个块设备,0755
是文件的权限(所有者可读、写、执行,其他用户可读和执行)。makedev(7, 0)
:这是设备号,makedev
函数用于生成设备号,7
是主设备号,0
是次设备号。对于环回设备,主设备号通常是 7。 主从设备号需要从机器里面通过ls -la /dev/block/loop*查看,不同的内核版本可能不一样
shell
rk3588_t:/ $ ls -l /dev/block/loop*
brwxr-xr-x 1 root root 7, 0 2025-01-13 00:17 /dev/block/loop0
brwxr-xr-x 1 root root 7, 8 2025-01-13 00:17 /dev/block/loop1
brw------- 1 root root 7, 80 2025-01-13 00:18 /dev/block/loop10
brw------- 1 root root 7, 88 2025-01-13 00:18 /dev/block/loop11
brw------- 1 root root 7, 96 2025-01-13 00:18 /dev/block/loop12
brw------- 1 root root 7, 104 2025-01-13 00:18 /dev/block/loop13
brw------- 1 root root 7, 112 2025-01-13 00:18 /dev/block/loop14
brw------- 1 root root 7, 120 2025-01-13 00:18 /dev/block/loop15
brwxr-xr-x 1 root root 7, 16 2025-01-13 00:17 /dev/block/loop2
brwxr-xr-x 1 root root 7, 24 2025-01-13 00:18 /dev/block/loop3
brw------- 1 root root 7, 32 2025-01-13 00:18 /dev/block/loop4
brw------- 1 root root 7, 40 2025-01-13 00:18 /dev/block/loop5
brw------- 1 root root 7, 48 2025-01-13 00:18 /dev/block/loop6
brw------- 1 root root 7, 56 2025-01-13 00:18 /dev/block/loop7
brw------- 1 root root 7, 64 2025-01-13 00:18 /dev/block/loop8
brw------- 1 root root 7, 72 2025-01-13 00:18 /dev/block/loop9
在init中编写代码将镜像文件绑定到loop设备上面
c++
std::string setup_loop_device(const std::string& file_path) {
std::string system_device;
if (Loop::create(file_path, system_device) != 0) {
LOG(ERROR) << "Failed to create loop device file_path";
return nullptr;
}
LOG(INFO) << "created loop device: " << system_device;
return system_device;
}
int Loop::create(const std::string& target, std::string& out_device) {
unique_fd ctl_fd(open("/dev/loop-control", O_RDWR | O_CLOEXEC));
if (ctl_fd.get() == -1) {
PLOG(ERROR) << "Failed to open loop-control";
return -errno;
}
int num = ioctl(ctl_fd.get(), LOOP_CTL_GET_FREE);
if (num == -1) {
PLOG(ERROR) << "Failed LOOP_CTL_GET_FREE";
for (size_t id = 0; id < 3; ++id) {
int ret = ioctl(ctl_fd.get(), LOOP_CTL_ADD, id);
LOG(INFO) << "LOOP_CTL_ADD ADD ID=" << id;
if (ret < 0 && errno != EEXIST) {
LOG(ERROR) << "Failed LOOP_CTL_ADD";
return -errno;
}
}
num = ioctl(ctl_fd.get(), LOOP_CTL_GET_FREE);
if (num == -1) {
PLOG(ERROR) << "Failed LOOP_CTL_GET_FREE";
return -errno;
}
}
out_device = StringPrintf("/dev/block/loop%d", num);
unique_fd target_fd;
for (size_t i = 0; i != kLoopDeviceRetryAttempts; ++i) {
target_fd.reset(open(target.c_str(), O_RDWR | O_CLOEXEC));
if (target_fd.get() != -1) {
break;
}
usleep(50000);
}
if (target_fd.get() == -1) {
PLOG(ERROR) << "Failed to open " << target;
return -errno;
}
if (!android::fs_mgr::WaitForFile(out_device, 2s)) {
LOG(ERROR) << "Failed to find " << out_device;
return -ENOENT;
}
unique_fd device_fd(open(out_device.c_str(), O_RDWR | O_CLOEXEC));
if (device_fd.get() == -1) {
PLOG(ERROR) << "Failed to open " << out_device;
return -errno;
}
if (ioctl(device_fd.get(), LOOP_SET_FD, target_fd.get()) == -1) {
PLOG(ERROR) << "Failed to LOOP_SET_FD";
return -errno;
}
struct loop_info64 li;
memset(&li, 0, sizeof(li));
strlcpy((char*)li.lo_crypt_name, kVoldPrefix, LO_NAME_SIZE);
if (ioctl(device_fd.get(), LOOP_SET_STATUS64, &li) == -1) {
PLOG(ERROR) << "Failed to LOOP_SET_STATUS64";
return -errno;
}
return 0;
}