我有一个2.4内核版本的Linux系统。我需要通过 device-mapper 为根分区创建一个映射设备,并在启动时挂载它。
我需要使用特殊的mapper类型(不是像线性或镜像这样的标准版)。所以,我尝试编写自己的内核模块,实现必要的功能(现在它只是将查询传输到真实设备)。
我使用this文章作为起点。我在代码中做了一些更改,现在它看起来像这样:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/device-mapper.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
#include <linux/bio.h>
#endif
#include <linux/fs.h>
#include <linux/kdev_t.h>
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
#include <linux/mm.h>
#endif
struct Sddm_target
{
struct dm_dev *dev;
sector_t start;
};
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
static int sddm_target_map(struct dm_target *ti, struct buffer_head *bh, int rw, union map_info *map_context)
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,32)
static int sddm_target_map(struct dm_target *ti, struct bio *bio, union map_info *map_context)
#else
static int sddm_target_map(struct dm_target *ti, struct bio *bio)
#endif
{
struct Sddm_target *mdt;
mdt = (struct Sddm_target *) ti->private;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
bh->b_dev = mdt->dev->bdev->bd_dev;
#else
bio->bi_bdev = mdt->dev->bdev;
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
submit_bh(rw, bh);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,32)
submit_bio(bio->bi_rw, bio);
#else
submit_bio(bio);
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
return 0;
#else
return DM_MAPIO_SUBMITTED;
#endif
}
static int sddm_target_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct Sddm_target *mdt;
unsigned long start;
unsigned long len;
int err;
if (argc != 2)
{
ti->error = "Invalid argument count";
return -EINVAL;
}
mdt = (struct Sddm_target*)kmalloc(sizeof(struct Sddm_target), GFP_KERNEL);
if (mdt == NULL)
{
printk(KERN_CRIT "\n Mdt is null\n");
ti->error = "dm-basic_target: Cannot allocate linear context";
return -ENOMEM;
}
if (sscanf(argv[1], "%lu", &start) != 1)
{
ti->error = "dm-basic_target: Invalid deviceee sector";
kfree(mdt);
printk(KERN_CRIT "\n>>out function basic_target_ctr with errorrrrrrrrrr \n");
return -EINVAL;
}
mdt->start = (sector_t)start;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
err = dm_get_device(ti, argv[0], ti->begin, ti->len, dm_table_get_mode(ti->table), &mdt->dev);
#else
err = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &mdt->dev);
#endif
if (err)
{
ti->error = "dm-basic_target: Device lookup failed";
kfree(mdt);
return -EINVAL;
}
ti->private = mdt;
return 0;
}
static void sddm_target_dtr(struct dm_target *ti)
{
struct Sddm_target *mdt = (struct Sddm_target *) ti->private;
dm_put_device(ti, mdt->dev);
kfree(mdt);
}
static struct target_type sddm_target = {
.name = "sddm_target",
.version = {1,0,0},
.module = THIS_MODULE,
.ctr = sddm_target_ctr,
.dtr = sddm_target_dtr,
.map = sddm_target_map,
};
static int __init init_sddm_target(void)
{
int result;
result = dm_register_target(&sddm_target);
return 0;
}
static void __exit cleanup_sddm_target(void)
{
dm_unregister_target(&sddm_target);
}
module_init(init_sddm_target);
module_exit(cleanup_sddm_target);
MODULE_LICENSE("GPL");
您看,主要功能是将目标设备更改为另一个(真实)并重新提交查询:
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
bh->b_dev = MKDEV(3, 3);
#else
bio->bi_bdev = mdt->dev->bdev;
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,4,32)
submit_bh(rw, bh);
#elif LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,32)
submit_bio(bio->bi_rw, bio);
#else
submit_bio(bio);
#endif
行bh->b_dev = MKDEV(3, 3);
错误,但我不知道相应的设备号位于何处,因此我尝试自行计算。
接下来我的步骤是更改 initrd 图片和 linuxrc 文件:
#!/bin/nash
echo "Loading dm-mod.o module"
insmod /lib/dm-mod.o
echo "Loading scsi_mod.o module"
insmod /lib/scsi_mod.o
echo "Loading sd_mod.o module"
insmod /lib/sd_mod.o
echo "Loading cdrom.o module"
insmod /lib/cdrom.o
echo "Loading sr_mod.o module"
insmod /lib/sr_mod.o
echo "Loading sg.o module"
insmod /lib/sg.o
echo "Loading usbcore.o module"
insmod /lib/usbcore.o
echo "Loading usb-storage.o module"
insmod /lib/usb-storage.o
sleep 5
echo "Loading jbd.o module"
insmod /lib/jbd.o
echo "Loading ext3.o module"
insmod /lib/ext3.o
insmod /lib//sddm_target.o
echo Mounting /proc filesystem
mount -t proc /proc /proc
echo Creating block devices
mkdevices /dev
echo Creating root device
echo "======================================"
ld-linux.so.2 /bin/dmsetup create root_part /opt/bin/table
echo "======================================"
mkrootdev /dev/root
echo 0x0100 > /proc/sys/kernel/real-root-dev
echo "MOUNT START==============="
mount -o acl,nosecdel,secrm --ro -t ext3 /dev/mapper/root_part /sysroot
echo "MOUNT DONE==============="
pivot_root /sysroot /sysroot/initrd
umount /initrd/proc
其中 sddm_target - 是我的内核模块。
表文件包含:
0 62814150 sddm_target /dev/hda3 0
映射设备出现在给定目录中,因此看起来一切都很好。但是当我尝试启动我的系统时,我会通过设备挂载调用几次 sddm_target_map 函数运行,然后启动保持并显示以下消息:
kjournald started. Commit intervel 5 seconds
一些谷歌搜索帮助我理解,这条消息是由文件系统检查程序打印的。但是它的原因是什么 - 我不知道。
我需要帮助!